java 如何在Quarkus中使用Uni和AsyncFile来预览大文件?

qjp7pelc  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(106)

如何在Quarkus中使用UniAsyncFile来提供大文件的预览,例如,video/mp4文件,同时从minio读取它?
我尝试使用Response类来实现它,遵循this,但没有成功:

@GET
    @Path("/download/{id}/ctx/{ctx}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response downloadFile(@PathParam("id") UUID fileId, @PathParam("ctx") String ctx, @QueryParam("preview") boolean preview,
                                 @HeaderParam(value = "Range") String httpRangeList) {
        try {

            ResFile resFile = resFileService.getResFile(fileId, ctx);
            String contentType = resFile.getMimeType();
            Long size = resFile.getSize();

            long rangeStart = 0;
            long rangeEnd = size - 1;

            if (preview) {

                if (httpRangeList == null) {
                    return Response.status(Response.Status.OK)
                            .header("Access-Control-Expose-Headers", HttpHeaders.CONTENT_DISPOSITION)
                            .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                            .header(HttpHeaders.CONTENT_TYPE, contentType)
                            .header("Accept-Ranges", "bytes")
                            .header("Content-Range", "bytes " + rangeStart + "-" + rangeEnd + "/" + size)
                            .header("Content-Length", String.valueOf(size))
                            .entity(resFileService.loadFileAsResourceRange(fileId, ctx, rangeStart, size)).build();
                } else {

                    String[] ranges = httpRangeList.split("-");
                    rangeStart = Long.parseLong(ranges[0].substring(6));
                    if (ranges.length > 1) {
                        rangeEnd = Long.parseLong(ranges[1]);
                    } else {
                        rangeEnd = rangeStart + chunkSize;
                    }

                    rangeEnd = Math.min(rangeEnd, size - 1);
                    final byte[] data = resFileService.loadFileAsResourceRange(fileId, ctx, rangeStart, rangeEnd).readAllBytes();

                    log.info("data size: {}", data.length);

                    final String contentLength = String.valueOf((rangeEnd - rangeStart) + 1);

                    if (rangeEnd >= size) {
                        return Response.status(Response.Status.OK)
                                .header("Access-Control-Expose-Headers", HttpHeaders.CONTENT_DISPOSITION)
                                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                                .header(HttpHeaders.CONTENT_TYPE, contentType)
                                .header("Accept-Ranges", "bytes")
                                .header("Content-Range", "bytes " + rangeStart + "-" + rangeEnd + "/" + size)
                                .header("Content-Length", contentLength)
                                .entity(data).build();
                    }
                    else {
                        return Response.status(Response.Status.PARTIAL_CONTENT)
                                .header("Access-Control-Expose-Headers", HttpHeaders.CONTENT_DISPOSITION)
                                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                                .header(HttpHeaders.CONTENT_TYPE, contentType)
                                .header("Accept-Ranges", "bytes")
                                .header("Content-Range", "bytes " + rangeStart + "-" + rangeEnd + "/" + size)
                                .header("Content-Length", contentLength)
                                .entity(data).build();
                    }
                }

            } else {

                return Response.status(Response.Status.OK)
                        .header("Access-Control-Expose-Headers", HttpHeaders.CONTENT_DISPOSITION)
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                        .header(HttpHeaders.CONTENT_TYPE, contentType)
                        .entity(resFileService.loadFileAsResource(fileId, ctx)).build();
            }
        } catch (NotFoundException e) {
            return Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build();
        } catch (IOException | MinIOException e) {
            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(MINIO_EXCEPTION, e.getMessage())).build();
        }
    }
public InputStream loadFileAsResource(UUID uuid, String ctx) throws MinIOException, NotFoundException {

        ResFile resFile = resFileRepository.findByResourceIdAndCtx(uuid, ctx).orElseThrow(() -> new NotFoundException(String.format(RESFILE_NOT_FOUND, uuid)));
        return minIOService.downloadFile(Buckets.FILES.name().toLowerCase(), resFile.getPath());
    }

    public ByteArrayInputStream loadFileAsResourceRange(UUID fileId, String ctx, Long rangeStart, Long rangeEnd) throws MinIOException, NotFoundException, IOException {

        ResFile resFile = resFileRepository.findByResourceIdAndCtx(fileId, ctx).orElseThrow(() -> new NotFoundException(String.format(RESFILE_NOT_FOUND, fileId)));

        Files.copy(minIOService.downloadFile(Buckets.FILES.name().toLowerCase(), resFile.getPath()),
                Paths.get("/tmp/" + resFile.getFileName()), StandardCopyOption.REPLACE_EXISTING);

        return new ByteArrayInputStream(IOUtils.toByteArray(new FileInputStream("/tmp/" + resFile.getFileName())), rangeStart.intValue(), rangeEnd.intValue());
    }
public InputStream downloadFile(String bucket, String filename) throws MinIOException {
        try {
            if(minioClient == null)
                initializeMinIOClient();
            // Get the object from bucket
            return minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(filename).build());
        } catch (Exception e) {
            throw new MinIOException(String.format("Error occurred while downloading file '%s' | ", filename), e);
        }
    }

this我读到了关于UniAsyncFile的内容。
但我不知道如何实施。
注意:我最好返回直接读取InputStream,而不保存从MinIO获取的文件

fzwojiic

fzwojiic1#

多亏了this
我能够用这种方法解决:

@GET
    @Path("/download/{id}/ctx/{ctx}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public CompletionStage<Response> downloadFile(@PathParam("id") UUID fileId, @PathParam("ctx") String ctx,
                                                  @QueryParam("preview") boolean preview, @HeaderParam("Range") String range) {

        ResFile resFile;
        try {
            resFile = resFileService.getResFile(fileId, ctx);
        } catch (NotFoundException e) {
            return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build());
        }

        if (preview) {

            if (range == null) {

                String contentType = resFile.getMimeType();

                return CompletableFuture.supplyAsync(() -> {
                    try {
                        return resFileService.loadFileAsResource(fileId, ctx);
                    } catch (MinIOException e) {
                        return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(SERVER_EXCEPTION, e)).build());
                    } catch (NotFoundException e) {
                        return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build());
                    }
                }).thenApplyAsync(file -> {
                    try {
                        return Response.ok((StreamingOutput) output -> {
                                    try (final InputStream is = (InputStream) file) {
                                        IOUtils.copyLarge(is, output);
                                    }
                                }).header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                                .header(HttpHeaders.CONTENT_TYPE, contentType)
                                .header(HttpHeaders.CONTENT_LENGTH, resFile.getSize())
                                .status(HttpStatus.SC_PARTIAL_CONTENT).build();
                    } catch (NotFoundException e) {
                        return Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build();
                    }
                }).handleAsync((r, e) -> {
                    if (e != null) {
                        log.error("Error", e);
                        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(SERVER_EXCEPTION, e)).build();
                    }
                    return r;
                });

            } else {

                String[] ranges = range.split("-");
                long rangeStart = Long.parseLong(ranges[0].substring(6));
                long rangeEnd;
                if (ranges.length > 1) {
                    rangeEnd = Long.parseLong(ranges[1]);
                } else {
                    rangeEnd = rangeStart + chunkSize;
                }

                log.info("@@@Range: {} - {}", rangeStart, rangeEnd);

                String contentType = resFile.getMimeType();

                rangeEnd = Math.min(rangeEnd, resFile.getSize() - 1);
                final String contentLength = String.valueOf((rangeEnd - rangeStart) + 1);
                long finalRangeEnd = rangeEnd;

                return CompletableFuture.supplyAsync(() -> {
                    try {
                        return resFileService.loadFileAsResource(fileId, ctx);
                    } catch (MinIOException e) {
                        return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(MINIO_EXCEPTION, e)).build());
                    } catch (NotFoundException e) {
                        return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build());
                    }
                }).thenApplyAsync(file -> {
                    try {
                        return Response.ok((StreamingOutput) output -> {
                                    try (final InputStream is = (InputStream) file) {
                                        long byets = IOUtils.copyLarge(is, output, rangeStart, finalRangeEnd);
                                        log.info("@@@Bytes: {}", byets);
                                    }
                                }).header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                                .header("Accept-Ranges", "bytes")
                                .header(HttpHeaders.CONTENT_TYPE, contentType)
                                .header(HttpHeaders.CONTENT_LENGTH, contentLength)
                                .header("Content-Range", "bytes " + rangeStart + "-" + finalRangeEnd + "/" + resFile.getSize())
                                .status(HttpStatus.SC_PARTIAL_CONTENT)
                                .build();
                    } catch (NotFoundException e) {
                        log.error("File not found", e);
                        return Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build();
                    }
                }).handleAsync((r, e) -> {
                    if (e != null) {
                        log.error("Error", e);
                        return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(SERVER_EXCEPTION, e)).build();
                    }
                    return r;
                });
            }
        } else {

            String contentType = resFile.getMimeType();

            return CompletableFuture.supplyAsync(() -> {
                try {
                    return resFileService.loadFileAsResource(fileId, ctx);
                } catch (MinIOException e) {
                    return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(MINIO_EXCEPTION, e)).build());
                } catch (NotFoundException e) {
                    return CompletableFuture.supplyAsync(() -> Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build());
                }
            }).thenApplyAsync(file -> {
                try {
                    return Response.ok((StreamingOutput) output -> {
                                try (final InputStream is = (InputStream) file) {
                                    IOUtils.copyLarge(is, output);
                                }
                            }).header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resFileService.getResFile(fileId, ctx).getFileName() + "\"")
                            .header(HttpHeaders.CONTENT_TYPE, contentType).build();
                } catch (NotFoundException e) {
                    return Response.status(Response.Status.NOT_FOUND).entity(String.format(FILE_NOT_FOUND, fileId)).build();
                }
            }).handleAsync((r, e) -> {
                if (e != null) {
                    log.error("Error", e);
                    return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(String.format(SERVER_EXCEPTION, e)).build();
                }
                return r;
            });
        }
    }

不需要UniAsyncFile

相关问题