需要做一个下载功能 把项目临时文件里的压缩包 下载下来 想用浏览器下载 用了 response.getOutputStream(); 但是为啥下载下来的文件要么打不开 要么就是显示空文件无法下载 参考了站内很多代码都不行
我直接返回io流给前端的话 是可以下载的 但是为啥会重复调用接口
有没有解释下 或者给个可以实现 response.getOutputStream() 文件下载的demo 可有偿
@POST
@Path("/test")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public FileInputStream test(@Context HttpServletRequest request, @Context HttpServletResponse response) {
FileInputStream fileInputStream = null;
try {
response.setContentType("application/zip");
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(文件名", "UTF-8"));
fileInputStream = new FileInputStream(new File(文件地址));
File file = new File(文件地址);
file.delete();
return fileInputStream;
} catch (Exception e) {
throw new RuntimeException("内部错误,请联系管理员!", e);
}
// finally {
// try {
// fileInputStream.close();
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// }
}
【以下回答由 GPT 生成】
首先,关于为什么直接将IO流返回给前端会重复调用接口的情况,主要是因为在使用response.getOutputStream()
时,服务器在写入完毕后并没有关闭流,导致客户端一直在等待数据。当客户端接收到数据后,会认为下载完成,然后自动再次发送请求,导致重复调用接口。
解决这个问题的一种方式是,在控制器方法中将response.getOutputStream()
方法返回的流内容写入到一个ByteArrayOutputStream
中,然后再将ByteArrayOutputStream
的内容作为字节数组返回给前端。这样可以确保流的数据被正确关闭,并且避免了重复调用接口的问题。
以下是示例代码的改进版:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
@Path("/download")
public class DownloadController {
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response downloadFile(@Context HttpServletRequest request) {
String filePath = "文件地址";
String fileName = "文件名";
File file = new File(filePath);
if (!file.exists()) {
return Response.status(Response.Status.NOT_FOUND).entity("文件不存在").build();
}
try {
FileInputStream fileInputStream = new FileInputStream(file);
StreamingOutput streamingOutput = new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException {
try {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} finally {
fileInputStream.close();
output.close();
}
}
};
return Response.ok(streamingOutput, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"))
.header("Content-Length", file.length())
.build();
} catch (IOException e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("服务器错误").build();
}
}
}
在此代码片段中,我们使用StreamingOutput
将文件流写入到输出流中,并在结束后关闭文件流和输出流。同时,我们返回一个Response对象,并设置了文件名和文件大小。这样浏览器就可以正确下载文件,而不会重复调用接口。
请注意,您需要替换代码中的"文件地址"和"文件名"为实际的路径和文件名。
希望这个解决方案对您有帮助!如果还有其他问题,请随时提问。
InputStream data = XXXXXXX; //接输入流
int n;
buf = new BufferedInputStream(data);
out = response.getOutputStream();
while ((n=buf.read())!=-1){
out.write(n);
}out.flush();