前言
最近遇到一个需求是这样的,我需要使用Feign去调用一个外部接口,以下就称该接口为api吧,这个api调用后是获取指定ip暴露的地址,携带参数去访问这个接口后,在客户端浏览器就会自动下载文件。
简单来说,就是访问一个URL然后浏览器就下载文件。
假如?
假如我想要在服务器截获这个文件呢?首先,这个需求明确的想要拿到这个文件,并保存服务器以供后续的操作,但是现在访问这个api接口却只能客户端下载,那我总不能去再写一个上传模块然客户端下载后去上传吧,这不现实。
方案一:
有的会说了,让对方把接口改掉,改变成以附件的形式传过来不就可以了吗?但是,这是需要远程调用的第三方接口,由于有些接口是诸如涉密平台,或者无法要求对方做出适配性改变的,那完蛋了,改变不了对方,遂放弃此方案。
方案二:
既然改变不了对方,那么我们只能改变我们自己了(卑微)。
首先,我们在本地环境可能不太好模拟出下载文件的场景,所以动手写一个实现一个访问接口,打开本地文件方式,并且可以在浏览器自动下载。以下你只需要把filePath
填好你自己的文件绝对路径即可打开。
第一步:
@GetMapping("/api/getFile")
public void downloadFile(HttpServletResponse response) throws IOException {
String filePath = "E:\\flyz\\test\\test-pdf.pdf"; //这里填入你的本地文件地址
File file = new File(filePath);
// 设置响应头,使浏览器能够开始下载文件
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
response.setContentType("application/octet-stream");
// 将文件内容写入响应输出流
try (InputStream inputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
response.getOutputStream().write(buffer, 0, bytesRead);
}
}
response.getOutputStream().flush();
}
ok!有了上述的基础实现,之后呢比如我已经打开我本地的服务了,暴露的ip和端口是http://localhst:8088/admin/api/getFile, 当我访问这个端口后浏览器就会去路径下载test-pdf.pdf这个文件,只要把这个路径当作远程调用的路径输入做测试即可。
那么进入第二步:
现在我要截取这个文件,并保存到我本地怎么实现呢?
@GetMapping("/api/callFeign")
public void callFeign() throws IOException {
String fileContentUrl = "***";
// 生成保存文件的路径
//自定义一个保存文件路径
String saveFilePath = "E:\\flyz\\save\\file.pdf";
// 下载文件并保存到本地
try (InputStream inputStream =
new URL(fileContentUrl).openStream();
FileOutputStream outputStream = new FileOutputStream(saveFilePath)) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
// 处理下载文件失败的情况
// ...
}
}
这里fileContentUr
就是填入你调用外部接口下载文件的地址,直接将你第一步的接口路径(http://localhst:8088/admin/api/getFile,)赋给fileContentUrl这个变量,而后调用,即可在saveFilePath这个自定义的保存路径上面查看到已经下载的文件了。
但是,这样也还不够,为了多加一条测试,可以打开Minio,上传一个文件后,将这个文件的分享下载路径导出,赋给fileContentUrl,再访问,也可以正常的截取到这个文件流,并下载在指定文件夹路径中而不会在浏览器上下载。
结语
自此,文件流截取下载也算是小试牛刀了!但是考虑到若不使用Feign而使用上述方式,在海量用户多线程的访问下,该方法的可靠性和稳定性肯定是大打折扣的,所以该种方式仍需要根据实际需求而定。而且图中将代码放置在控制层仅仅是为了方便,最好还是规范一点放在服务层,保存文件后一般需要同步存储逻辑到数据库当中,少不了CRUD,所以最好是在服务层写代码并确定好事务,以及异常回滚等。
若有使用PageOffice的,想必也有需要word转换成pdf文件的需求,可以参考我的下一篇基于com.aspose.words实现的转换方法,代码量非常少,通俗易懂。