Feign上传和下载文件功能

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

Feign上传下载

问题背景

基于目前一些主流的框架,基本上都会用到微服务的架构,很多时候会将file文件管理的功能,抽取到一个独立的微服务例如file微服务上面。

前端的请求,都统一的调用file微服务进行文件的上传下载的功能!!!

这样的设计,好像是没啥毛病,统一管理嘛!!!

image.png

因为文件上传,可能还需要写入业务数据,例如,附件的信息等,这就不得不抽取成一个独立的微服务,供前端去使用了。

那就会有个问题呀:!!!T_T

1.如果我的附件不是通过前端上传的呢?我是一个后端的服务,需要保存一个附件,那你咋搞嘛?

2.我后端的一个服务,需要读取一个文件,进行解析,因为是分布式的架构,可能file微服务部署到服务器A,咋们后端服务部署在服务B,这样,根据磁盘路径,根本就无法读取到文件,那你又怎么处理呢?

嗯嗯嗯,你说的都很有道理,这确实是个大问题呀!!!

image.png

别慌,咋们今天就来解决这个问题!!!

因为我们服务之间接口的调用,在微服务体系中,一般都是通过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(),否则就算获取到该流,也无法处理业务逻辑。

image.png

好了,上面就是咋们定义好的feign接口,和提供服务的file微服务上传下载接口!!!

上传下载接口,只是给出一个demo,大家伙,可自行修改,相应的业务逻辑!!!^_^

Feign上传下载

接下来,咋们就开始使用到这个feign上传下载功能!!!

image.png

  • 上传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流被关闭了,无法再使用,即不能处理业务逻辑代码了!!!

image.png

好了,这个就是上传文件的示例,也是比较简单啦!!!

好了,Feign上传和下载,大概的实现,就是这样了!!!^_^

那我们就可以愉快的编写代码了!!!^_^

image.png

猜你喜欢

转载自juejin.im/post/7086827087260024845