1. 版本信息
- SpringBoot与SpringCloud的版本依赖如下(pom.xml)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- OpenFeign 的版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- OpenFeign-form依赖 (上传下载会用到,如果单纯用OpenFeign请求不需要引入)
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.4.1</version>
</dependency>
2. 定义请求的接口文件
- 上传接口
@FeignClient(
url = "${api.upload.host}",
name = "API-Uploader",
configuration = APIUploader.UploadConfig.class)
@Service
public interface APIUploader {
@PostMapping(value = "${api.upload.uri}",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
RespData uploadDataFile(@RequestParam Map<String, String> map, @Param(value = "file") MultipartFile file);
@Slf4j
class UploadConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignFormEncoder () {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
@Bean
public Logger feignLogger(){
return new Logger(){
@Override
protected void log(String s, String s1, Object... objects) {
log.info(String.format(methodTag(s) + s1, objects));
}
};
}
}
}
需要注意以下几点:
-
api.upload.host 与 api.upload.uri 需要在SpringBoot的application.yml文件中配置
-
通过修改UploadConfig.feignLoggerLevel 的日志级别来控制显示日志
-
上传的文件为MultipartFile,在上传前需要对文件进行转化,转化代码如下
public static MultipartFile toMultipartFile(String filepath) throws IOException {
File file = new File(filepath);
FileItem fileItem = new DiskFileItem("file", Files.probeContentType(file.toPath()),false,file.getName(),(int)file.length(),file.getParentFile());
byte[] buffer = new byte[4096];
int n;
InputStream inputStream = new FileInputStream(file);
OutputStream os = fileItem.getOutputStream();
while ( (n = inputStream.read(buffer,0,4096)) != -1){
os.write(buffer,0,n);
}
//注意关闭文件流防止内存泄露
inputStream.close();
os.close();
MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
return multipartFile;
}
- 上传请求
//注入
@AutoWired
APIUploader uploader;
// 省略业务代码
//获取请求参数,细节省略
Map<String,String> requestParams = apiUtil.getRequestParams();
//本地文件路径
String localFile = "/path/to/file"
RespData respData = uploader.uploadDataFile(requestParams, FileUtil.toMultipartFile(localFile));
//判断结果
if (respData.getCode() == apiUtil.API_RESP_CODE_OK) {
log.info("local file {} upload success,response {}",localFile,respData.getData());
}else {
log.error("local file {} upload failed,response {}",localFile,respData.getMessage());
}
- 下载接口
@FeignClient(
url = "${api.download.host}",
name = "API-Downloader",
configuration = APIDownloader.DownloadConfig.class)
@Service
public interface APIDownloader {
@RequestMapping(value = "/{fileURI}")
byte[] download(@RequestHeader("Authorization") String authHeader, @PathVariable("fileURI") String fileURI);
@Slf4j
class DownloadConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Decoder feignDecoder () {
List<HttpMessageConverter<?>> springConverters =
messageConverters.getObject().getConverters();
List<HttpMessageConverter<?>> decoderConverters =
new ArrayList<HttpMessageConverter<?>>(springConverters.size() + 1);
decoderConverters.addAll(springConverters);
decoderConverters.add(new SpringManyMultipartFilesReader(4096));
HttpMessageConverters httpMessageConverters = new HttpMessageConverters(decoderConverters);
return new SpringDecoder(new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() {
return httpMessageConverters;
}
});
}
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
@Bean
public Logger feignLogger(){
return new Logger(){
@Override
protected void log(String s, String s1, Object... objects) {
log.info(String.format(methodTag(s) + s1, objects));
}
};
}
}
}
注意以下事项:
- @RequestHeader(“Authorization”) String authHeader 指的是需要http auth认证的头信息内容,如果不需要可以置空
- 跟上传一样api.download.host需要在application.yml文件中配置
- @PathVariable(“fileURI”) String fileURI 指的是下载文件的URI,下载的完整路径应该${api.download.host} + fileURI
- 请求返回的byte[]的字节流,需要写入本地文件,对应的方法如下:
public static void writeBytesToLocalFile(String localFilePath,byte[] bytes) throws IOException {
OutputStream outputStream = new FileOutputStream(localFilePath);
outputStream.write(bytes);
outputStream.close();
}
- 下载请求代码
//注入
@AutoWired
APIDownloader downloader;
// 省略业务代码
// 设置下载文件的URI
String remoteFileURI = "/remotepath/to/file";
// 设置http auth请求的信息
String authHeader = "";
if(enableAuth) {
authHeader = "Basic " + Encryptor.base64encode(authUser + ":" + authPassword);
}
String localFile = "/path/to/file";
FileUtil.writeBytesToLocalFile(localFile,downloader.download(authHeader,remoteFileURI));