在springcloud微服务中,需要用到feign去调用文件上传的服务,如通过fastdfs文件服务器上传文件:
1、fegin的接口配置(服务降级代码:略~)
@FeignClient(value = "XXXXXXXX-XXXXX-PROVIDER", fallbackFactory = XxxxxxClientFallbackFactory.class)
public interface XxxxxxClientService {
/**
* 保存图片
*
* @param file
* @return
* @throws Exception
*/
@RequestMapping(value = "/xxxxx/xxxxx/saveFile", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result saveFile(@RequestPart("file") MultipartFile file) throws Exception;
}
2、服务入口代码:
/**
* 保存文件
*
* @param file
* @return
* @throws Exception
*/
@RequestMapping(value = "/xxxxx/xxxxx/saveFile", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result saveFile(@RequestPart("file") MultipartFile file) throws Exception {
try {
return xxxxxxClientService.saveFile(file);//fegin接口服务调用
} catch (Exception e) {
log.error("~~~~", e);
}
return Result.error();
}
3、文件上传服务(单独访问该服务,上传文件成功~)
@RequestMapping(value = "/xxxxxx/saveFile", method = RequestMethod.POST)
public Result saveFile(@RequestPart("file") MultipartFile file) throws Exception {
if (file == null) {
return new Result().put("code", "900001").put("msg", "对不起,文件保存失败").put("imgUrl", "");
} else {
String imgUrl = dfsClient.uploadFile(file); //利用fastdfs上传文件
return new Result().put("code", "0").put("msg", "文件保存成功").put("imgUrl", imgUrl);
}
}
4、FastDFS文件服务器配置:(依赖、配置等略)
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
@Component
public class FastDFSClientWrapper {
private static final Logger log = LoggerFactory.getLogger(FastDFSClientWrapper.class);
@Autowired
private FastFileStorageClient storageClient;
@Value("${fdfs.resHost}")
private String resHost;
@Value("${fdfs.storagePort}")
private String storagePort;
/**
* 上传文件
*
* @param file 文件对象
* @return 文件访问地址
* @throws IOException
*/
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null);
return getResAccessUrl(storePath);
}
/**
* 将一段字符串生成一个文件上传
*
* @param content 文件内容
* @param fileExtension
* @return
*/
public String uploadFile(String content, String fileExtension) {
byte[] buff = content.getBytes(Charset.forName("UTF-8"));
ByteArrayInputStream stream = new ByteArrayInputStream(buff);
StorePath storePath = storageClient.uploadFile(stream, buff.length, fileExtension, null);
return getResAccessUrl(storePath);
}
// 封装图片完整URL地址
private String getResAccessUrl(StorePath storePath) {
String fileUrl = "http://" + resHost
+ ":" + storagePort + "/" + storePath.getFullPath();
return fileUrl;
}
/**
* 删除文件
*
* @param fileUrl 文件访问地址
* @return
*/
public void deleteFile(String fileUrl) {
if (StringUtils.isEmpty(fileUrl)) {
return;
}
try {
StorePath storePath = StorePath.praseFromUrl(fileUrl);
storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
} catch (FdfsUnsupportStorePathException e) {
log.warn(e.getMessage());
}
}
}
通过入口服务访问,会出现报错如下:
Caused by: feign.codec.EncodeException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile] and content type [multipart/form-data]
at org.springframework.cloud.netflix.feign.support.SpringEncoder.encode(SpringEncoder.java:113) ~[spring-cloud-netflix-core-1.3.1.RELEASE.jar:1.3.1.RELEASE]
at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:351) ~[feign-core-9.5.0.jar:na]
at feign.ReflectiveFeign$BuildTemplateByResolvingArgs.create(ReflectiveFeign.java:213) ~[feign-core-9.5.0.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:72) ~[feign-core-9.5.0.jar:na]
at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:108) ~[feign-hystrix-9.5.0.jar:na]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:302) ~[hystrix-core-1.5.12.jar:1.5.12]
at com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:298) ~[hystrix-core-1.5.12.jar:1.5.12]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) ~[rxjava-1.1.10.jar:1.1.10]
... 26 common frames omitted
1、pom.xml中添加依赖:
io.github.openfeign.form
feign-form
3.0.3
io.github.openfeign.form
feign-form-spring
3.0.3
2、添加配置类:
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
@Configuration
public class FeignMultipartSupportConfig {
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringFormEncoder();
}
@Bean
public feign.Logger.Level multipartLoggerLevel() {
return feign.Logger.Level.FULL;
}
}
3、再通过fegin的方式去调用上传文件的服务:
{"msg":"文件保存成功","fileUrl":"http://xxx.xxx.xxx.xxx/group1/M00/00/00/Co1uzFzWlz6AZWC2AAltu9tu2nA760.png","code":"0"}
希望能解决路过人的问题。