前言
通常在spring-boot 项目中,对于文件的下载都是直接调用到对应的服务中,而不是通过feign 接口获取文件;有时我们在对接外部接口时,因为权限等问题,不能直接暴露文件服务,会有一个专门对外的服务进行对接,但是我们又要利用现有的文件服务逻辑,此时可以考虑使用feign 完成文件的获取。
一、feign接口获取文件流程:
我们知道feign 只是通过动态代理为我们构建了http 的请求,显然我们不能通过feign 接口直接把 HttpServletResponse 传过去,因为feign接口服务的提供者,接收到的HttpServletResponse 和我们通过feign 接口传入的压根儿就不是同一个对象,所以此时我们只能在文件服务中返回文件流,然后在将文件流 写入到最开始HttpServletResponse 对象中,最后返回给浏览器,流程大概如下:
二、文件获取实现
2.1 引入jar:
因为我们是web 服务并且使用了feign 接口所有这个两个jar 依赖是必须要有的:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.2 实现:
(1) feign 接口:
@GetMapping(value = "/osp/download/{id}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
ResponseEntity<Resource> download(@PathVariable("id") String id);
(2)feign 接口服务提供者:
控制器:
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
@GetMapping("/osp/download/{id}")
public ResponseEntity<Resource> ospDownloadFile(@PathVariable String id) throws Exception {
return xxxService.ospDownloadFile(id);
}
xxxService 对应自己业务里面的实现;实现类:
@Override
public ResponseEntity<org.springframework.core.io.Resource> ospDownloadFile(String id) throws Exception {
// 这里获取自己业务中的文件
FileRecord fileRecord = fileRecordService.selectCache(id);
if (null == fileRecord)
throw new Exception("文件不存在");
InputStream inputStream = null;
ByteArrayOutputStream outputStream = null;
try {
inputStream = getObjectInputStream(fileRecord.getCodeName());
outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
byte[] byteArray = outputStream.toByteArray();
// 读取文件内容
ByteArrayResource resource = new ByteArrayResource(byteArray);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + java.net.URLEncoder.encode(fileRecord.getName(),"UTF-8"));
// 返回响应实体
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
} finally {
if (null != inputStream) {
inputStream.close();
}
if (null != outputStream) {
outputStream.close();
}
}
}
(3)对外服务端:
对外服务控制器:
@GetMapping("/file/download/{id}")
public void download(@PathVariable String id,HttpServletResponse response) throws Exception {
ospFlowService.ospDownLoadFile(id,response);
}
业务实现类:
@Override
public void ospDownLoadFile(String id, HttpServletResponse response) throws Exception {
// feign 接口获取文件流
ResponseEntity<Resource> fileResponse = remoteFileService.download(id);
// 设置响应头
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, fileResponse.getHeaders().get(HttpHeaders.CONTENT_DISPOSITION).get(0));
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
// 从 Feign 响应中获取文件输入流,并写入到 HttpServletResponse 输出流中
InputStream inputStream = fileResponse.getBody().getInputStream();
OutputStream output = response.getOutputStream();
IoUtil.copy(inputStream, output);
// 将流刷新给到浏览器
response.flushBuffer();
}
这里使用cn.hutool.core.io 中的 IoUtil 工具类,有需要的可以引入
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
总结
本文通过feign 接口完成文件的下载。