需求:从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. console.table(),在控制台以表格形式输出对象

    今天给大家安利一个属性,console.table(). 它的作用在控制台以表格的形式显示object.这样看起来是不是更方便了呢. var aaa = [ {index:0,name:"1 ...

  2. [十二省联考2019]D2T2春节十二响

    嘟嘟嘟 这题真没想到这么简单-- 首先有60分大礼:\(O(n ^ 2logn)\)贪心.(我也不知道为啥就是对的) 然后又送15分链:维护两个堆,每次去堆顶的最大值. 这时候得到75分已经很开心了, ...

  3. 三。Hibernate 注解形式

    Hibernate支持JPA注解的jar包 JPA全称: Java Persistence API JPA和Hibernate之间的关系,可以简单的理解为JPA是标准接口,Hibernate是实现. ...

  4. 类SimpleDateFormat

    概述 java.text.DateFormat 是日期/时间格式化子类的抽象类,不能直接使用.我们通过这个类的子类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行 ...

  5. Centos 7(linux)系统下如何给jar应用程序创建桌面快捷方式

    1.创建系统自带的应用程序快捷方式 对于系统自带的应用程序,其桌面快捷方式存储的位置为以下三个目录中的其中一个: /usr/share/applications ~/.local/share/appl ...

  6. Appuim的安装步骤

    1.下载Appium Desktop并安装 下载地址:https://github.com/appium/appium-desktop/releases 我下载的版本为:appium-desktop- ...

  7. jquery中关键字写错导致的错误——dataType写成dateType(data写成date)

    由于不会报错,会导致原本servlet后端传回的json字符串不能被正确解析为json格式,而只是显示为字符串. 具体错误表现为:在浏览器Console中显示为字符串,但是在json.cn中可以被正常 ...

  8. mysql和mariadb备份工具xtrabackup和mariabackup(mariadb上版本必须用这个)

    简介 xtraBackup(PXB) 工具是 Percona 公司用 perl 语言开发的一个用于 MySQL 数据库物理热备的备份工具,支持 MySQl(Oracle).Percona Server ...

  9. Python静态网页爬取:批量获取高清壁纸

    前言 在设计爬虫项目的时候,首先要在脑内明确人工浏览页面获得图片时的步骤 一般地,我们去网上批量打开壁纸的时候一般操作如下: 1.打开壁纸网页 2.单击壁纸图(打开指定壁纸的页面) 3.选择分辨率(我 ...

  10. ajax基本原理与案例

    一.什么是Ajax AJAX即“Asynchronous Javascript And XML”( 异步 JavaScript和XML),AJAX不是一种新的编程语言,而是一种用于创建更好更快以及交互 ...