需求:从ftp取文件并http调用某接口上传此文件

偷懒的话可以从ftp上取文件存到本地,再调用接口上传文件,如下

String ftpPath = "/ftp/path/file.bin";
RestTemplate restTemplate = new RestTemplateBuilder().build();
FtpCilent ftp = new FtpClient();
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.setCharset("utf-8");
ftp.setControlEncoding("utf-8");
……// ftp连接并登陆
File tmpFile = File.createTempFile(UUID.randomUUID().toString, null);
try(OutputStream outputStream = new FileOutputStream(tmpFile)){
ftp.retreiveFile(ftpPath, outputStream);// 保存到本地
}
ftp.disconnect();
MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap<>();
dataMap.add("filename", new FileSystemResource(tmpFile));// 添加文件到表单
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(dataMap, requestHeaders);
restTemplate.exchange(...);
tmpFile.delete();

如上即可完成需求,但如果只是这样的话我肯定不会水这一贴了,这样做有个很明显的缺点,要先将文件下载到本地,再将此文件上传,分成了两步,还多了个临时文件得删,而下面的改进版代码会将两步合并为一步提高效率并不额外占用磁盘空间。

String ftpPath = "/ftp/path/file.bin";
RestTemplate restTemplate = new RestTemplateBuilder().build();
FtpCilent ftp = new FtpClient();
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.setCharset("utf-8");
ftp.setControlEncoding("utf-8");
.....// ftp连接并登陆
FTPFile ftpFile = ftp.mlistFile(ftpPath);// 获取文件信息
try(InputStream in = ftp.retreiveFileStream(ftpPath);){
InputStreamResource fileResource = new InputStreamResource(in){
@Override
public long contentLength(){
return ftpFile.getSize();
} @Override
public String getFilename(){
return ftpFile.getName();
}
};
MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap<>();
dataMap.add("filename", fileResource);// 添加文件到表单
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(dataMap, requestHeaders);
restTemplate.exchange(...); ftp.disconnect();
}

总体思路就是将FileSystemResource换成了InputStreamResource,但这里有两个重点,我重写了它的contentLength方法和getFilename方法

先说getFilename,如果不重写这个方法,并且文件有一定大小,那么服务端会出现异常

The multi-part request contained parameter data (excluding uploaded files) that exceeded

这时你百度会看到人让你设置什么max-request-size啥的,但没用的,我试过设置几个G也没用还是上传不了几十M的文件,有必要设置文件名。

再说contentLength,如果不重写这个方法会出现异常

do not use inputstreamresource if a stream needs to be read multiple times

经排查,原因是在上传文件时resttemplate会通过这个方法得到inputstream的大小,而这个方法会直接读取inputstream的所有数据来得到大小,当它真正要读取内容的时候发现流已经被读完了,不得不说这方法实现的非常滑稽,有必要重写这个方法。

RestTemplate通过InputStreamResource上传文件的更多相关文章

  1. 使用RestTemplate调用接口上传文件

    场景 接口接受一个文件,缓存在本地,验证文件的完整性及内容,然后将文件上传至云服务器: 下面只写利用RestTemplate将文件上传至云服务器,至于文件上传以及缓存在本地可以参考:JAVA文件上传: ...

  2. 通过`RestTemplate`上传文件(InputStreamResource详解)

    通过RestTemplate上传文件 1.上传文件File 碰到一个需求,在代码中通过HTTP方式做一个验证的请求,请求的参数包含了文件类型.想想其实很简单,直接使用定义好的MultiValueMap ...

  3. Java模拟http上传文件请求(HttpURLConnection,HttpClient4.4,RestTemplate)

    先上代码: public void uploadToUrl(String fileId, String fileSetId, String formUrl) throws Throwable { St ...

  4. RestTemplate OR Spring Cloud Feign 上传文件

    SpringBoot,通过RestTemplate 或者 Spring Cloud Feign,上传文件(支持多文件上传),服务端接口是MultipartFile接收. 将文件的字节流,放入ByteA ...

  5. RestTemplate上传文件

    1.上传的文件是File类型 如果文件保存在本地,即可以通过File file = new File(path) 或者 文件路径地址获取到指定文件 public String uploadFile(F ...

  6. restTemplate.postForObject上传文件中文乱码(???.xls)

    一.问题描述 项目中, 使用restTemplate上传文件时, 文件名中文乱码, 一串问号, 源文件名为: 测试中文乱码哦哦哦.zip, 通过restTemplate.postForObject调用 ...

  7. resttemplate 文件上传 上传文件

    springmvc RestTemplate文件上传 RestTemplate上传文件总结

  8. Spring Boot 上传文件 获取项目根路径 物理地址 resttemplate上传文件

    springboot部署之后无法获取项目目录的问题: 之前看到网上有提问在开发一个springboot的项目时,在项目部署的时候遇到一个问题:就是我将项目导出为jar包,然后用java -jar 运行 ...

  9. 【Spring Boot】关于上传文件例子的剖析

    目录 Spring Boot 上传文件 功能实现 增加ControllerFileUploadController 增加ServiceStorageService 增加一个Thymeleaf页面 修改 ...

随机推荐

  1. CentOS 安装 ceph 单机版(luminous版本)

    一.环境准备 CentOS Linux release 7.4.1708 (Core)一台,4块磁盘(sda.sdb,.sdc.sdd) 192.168.27.130 nceph 二.配置环境 1.修 ...

  2. php之微信公众号发送模板消息

    讲一下开发项目中微信公众号发送模板消息的实现过程(我用的还是Thinkphp5.0). 先看一下效果,如图: 就是类似于这样的,下面讲一下实现过程: 第一步:微信公众号申请模板消息权限: 立即申请: ...

  3. pytorch的函数中的dilation参数的作用

    如果我们设置的dilation=0的话,效果如图: 蓝色为输入,绿色为输出,可见卷积核为3*3的卷积核 如果我们设置的是dilation=1,那么效果如图: 蓝色为输入,绿色为输出,卷积核仍为3*3, ...

  4. 在Winform开发框架中对附件文件进行集中归档处理

    在我们Winform开发中,往往需要涉及到附件的统一管理,因此我倾向于把它们独立出来作为一个附件管理模块,这样各个模块都可以使用这个附件管理模块,更好的实现模块重用的目的.在涉及附件管理的场景中,一个 ...

  5. Element ui 日期限制范围

    时间限定范围: <el-date-picker type="date" placeholder="选择日期" v-model="addForm. ...

  6. 使用.Net Core Mvc +SqlSugar +Autofac+AutoMapper+....

    开源地址:https://github.com/AjuPrince/Aju.Carefree 目前用到了 SqlSugar.Dapper.Autofac.AutoMapper.Swagger.Redi ...

  7. LIS ZOJ - 4028

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4028 memset超时 这题竟然是一个差分约束 好吧呢 对于每一个a[i] ...

  8. python3 实例方法、类方法和静态方法

    #!/usr/bin/env python3.6 #-*- coding:utf-8 -*- # class Person(object): city = 'Beijing' def __init__ ...

  9. LeetCode--11_974_Subarray_Sums_Divisible_by_K

    题目链接:点击这里 public static int subarraysDivByK(int[] A, int K) { int ans = 0,sum = 0; int[] B = new int ...

  10. 修改CentOS6.5默认主机名(root下操作)

    使用CentOS6.5官方镜像安装完毕之后,默认的主机名为localhost,不便管理,我们需要根据实际情况修改. 此处我准备讲默认的主机名 localhost 改为 comex01-ct65 第一步 ...