需求:从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. FreeHttp (a fiddler add in to temper the http)

    introduction FreeHttp is a Fiddler plugin. With FreeHttp you can modify the request or response mess ...

  2. Neutron vxlan network--L2 Population

    L2 Population 是用来提高 VXLAN 网络 Scalability 的.   通常我们说某个系统的 Scalability 好,其意思是: 当系统的规模变大时,仍然能够高效地工作. L2 ...

  3. 移除 iview的Table组件固定两头后box-shadow阴影效果

    .ivu-table-fixed{ box-shadow:0 0 0 #fff; }

  4. JS学习笔记:(一)浏览器页面渲染机制

    浏览器的内核主要分为渲染引擎和JS引擎.目前市面上常见的浏览器内核可以分为这四种:Trident(IE).Gecko(火狐).Blink(Chrome.Opera).Webkit(Safari).这里 ...

  5. vue cli使用融云实现聊天

    公司有个项目要实现一个聊天功能,需求如下图,略显随意 公司最终选择融云这个吊炸天的即时通信,文档详细的一匹,刚开始看文档感觉很详细实现起来也不麻烦,有很多开源的demo可以在线演示和下载 不过我们的项 ...

  6. Android一些问题

    1.wait()与sleep() wait()方法会释放占有的对象锁,当前线程进入等待池,释放cpu, 而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序: sleep()方法则表示,当前线程 ...

  7. MAVEN打包同时引入本地jar包

    方法一(pom文件指定jar包目录进行引入) 1.将需要手动引入的包放在项目目录下,如lib目录下: 修改pom文件,引入依赖并且将scope设置为system 2.同时配置maven打包插件 方法二 ...

  8. LVS负载均衡DR模式实现

    LVS负载均衡之DR模式配置 DR 模式架构图: 操作步骤 实验环境准备:(centos7平台) 所有服务器上配置 # systemctl stop firewalld //关闭防火墙 # sed - ...

  9. bzoj3678 Katu Puzzle

    题目链接 题意 给定一张图,对于每条边给出一个运算符\((\&,|,\otimes)\)和一个值\(c(0 \le c \le 1)\).问能否通过给每个点赋上一个值.使得每条边通过指定的运算 ...

  10. IIS8的SNI功能实现同一服务器多HTTPS站点

    名词解释: SNI指是一项用于改善SSL/TLS的技术,在SSLv3/TLSv1中被启用.它允许客户端在发起SSL握手请求时(具体说来,是客户端发出SSL请求中的ClientHello阶段),就提交请 ...