一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
Feign上传下载
问题背景
基于目前一些主流的框架,基本上都会用到微服务
的架构,很多时候会将file
文件管理的功能,抽取到一个独立的微服务
例如file微服务
上面。
前端的请求,都统一的调用file微服务
进行文件的上传
和下载
的功能!!!
这样的设计,好像是没啥毛病,统一管理嘛!!!
因为文件上传,可能还需要写入业务数据
,例如,附件的信息
等,这就不得不抽取成一个独立的微服务,供前端
去使用了。
那就会有个问题呀:!!!T_T
1.如果我的附件不是通过前端上传的呢?我是一个后端的服务,需要保存一个附件,那你咋搞嘛?
2.我后端的一个服务,需要读取一个文件,进行解析,因为是分布式的架构,可能
file微服务
部署到服务器A
,咋们后端服务
部署在服务B
,这样,根据磁盘路径
,根本就无法读取到文件,那你又怎么处理呢?
嗯嗯嗯,你说的都很有道理,这确实是个大问题呀!!!
别慌,咋们今天就来解决这个问题!!!
因为我们服务之间接口的调用,在微服务
体系中,一般都是通过feign
去调。那么文件这块,能不能也通过feign
去调用呢?
答案,肯定是可以的呀,哈哈!!!^_^
那废话不多说,上代码!!!
Feign接口准备
- 定义一个
Feign
上传,下载的接口
@FeignClient(name = "file", configuration = {FileClient.MultipartSupportConfig.class})
public interface FileClient {
/**
* 上传文件
* @param file
* @return
*/
@RequestMapping(path = "/file/upload", consumes = {"multipart/form-data"})
JsonResult upload(@RequestPart(name="file") MultipartFile file);
/**
* 下载文件
*/
@GetMapping(path = "/file/download/{fileId}")
Response download(@PathVariable(name = "fileId") String fileId);
public class MultipartSupportConfig {
@Bean
@Primary
@Scope("prototype")
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
}
复制代码
file微服务
提供文件上传
接口
@RequestMapping("/file/upload")
public JsonResult upload(MultipartHttpServletRequest request) throws Exception {
JsonResult jsonResult = new JsonResult();
String timestamp = request.getParameter("time");
MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
List<MultipartFile> files = multiFileMap.get("files");
if (BeanUtil.isEmpty(files)) {
files = multiFileMap.get("file");
}
Iterator<MultipartFile> it = files.iterator();
while (it.hasNext()) {
MultipartFile multipartFile = it.next();
//保存到磁盘
multipartFile.transferTo(new File("文件路径"));
//记录文件上传业务数据
...
xxxxFileDao.saveFile(xxxFile);
}
jsonResult.setSuccess(true);
jsonResult.setData(fileList);
jsonResult.setMessage("成功上传!");
return jsonResult;
}
复制代码
file微服务
提供文件下载
接口
@GetMapping("/download/{fileId}")
public void feigndownloadOne(@PathVariable("fileId") String fileId, HttpServletResponse response) throws Exception {
//通过fileId查找文件
...
xxxFile = xxxxFileDao.getFile(fileId);
File file = new File("文件路径");
String filename = xxxFile.getName();
String type ="attachment";
response.setHeader("Content-Disposition", type + ";filename=" + filename);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream buff = null;
OutputStream out = null;
try {
buff = new BufferedInputStream(fis);
out = response.getOutputStream();
IOUtils.copy(buff, out);
} finally {
out.flush();//注意out流,对象不能close
fis.close();
buff.close();
}
}
复制代码
下载
这个接口,有个比较重要的地方就是,out
流,不能close()
,否则就算获取到该流,也无法处理业务逻辑。
好了
,上面就是咋们定义好的feign接口,和提供服务的file微服务
上传下载接口!!!
上传下载接口,只是给出一个demo,大家伙,可自行修改,相应的业务逻辑!!!^_^
Feign上传下载
接下来,咋们就开始使用到这个feign
的上传下载
功能!!!
- 上传
feign接口
,使用
import java.io.File;
import java.io.FileInputStream;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.mock.web.MockMultipartFile;
import org.apache.http.entity.ContentType;
File pdfFile = new File("D://test.pdf");
FileInputStream fileInputStream = new FileInputStream(pdfFile);
MultipartFile multipartFile = new MockMultipartFile(pdfFile.getName(), pdfFile.getName(),
ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
//上传
JsonResult jsonResult = fileClient.upload(multipartFile);
if (jsonResult.isSuccess() && jsonResult.getCode() == 200) {
}
复制代码
注意了
注意了
注意了
!!!
这里,有个要注意的地方,因为我们的
upload
接口,即controller
接口一般使用MultipartFile
对象接收文件,那么我们就得把File
,对象先转成MultipartFile
对象,才可以调通这个接口!!!转换方式,看上面代码即可!!!
好了,这个就是上传文件的示例
,也是比较简单
啦!!!
- 下载
feign接口
,使用
import feign.Response;
//文件流
Response response = fileClient.download(fileId);
InputStream in = null;
if(response.status() == 200){
Response.Body body = response.body();
in = body.asInputStream();
//拿到这个in流,处理相应的业务逻辑
...
//处理完成后,记得关闭一下inputStream流
if(in != null){
in.close();
}
}
复制代码
注意了
注意了
注意了
!!!
这里有两个地方需要注意:
1.因为我们的download接口,
out
流是还没有close()
,所以这里的in
流,用完得close()
一下。2.这里的代码,在开发过程中,不能
打断点调试
,不能打断点调试
,不能打断点调试
!!!重要的事情得说三遍,不能
打断点调试
,因为你断点调试后
,这里的in
流,会因为执行了toString()
方法,导致in
流被关闭
了,无法再使用,即不能处理业务逻辑代码了!!!
好了,这个就是上传文件的示例
,也是比较简单
啦!!!
好了,Feign
上传和下载,大概的实现,就是这样了!!!^_^
那我们就可以愉快的编写代码了!!!^_^