单服务中使用MultipartFile上传文件没有问题,但Cloud中使用Feign文件上传就会有问题,不会自动跳到下一个服务中,查了下原来Feign默认不支持,后来通过三方的依赖包实现。
添加三方依赖包
Feign客户端中添加依赖配置,注意,一定要是>=3.0.0。
3.0.0之前的版本有Bug,通过feign-form实现文件上传,会导致无法解码@Requestboby中传递的Map、User等等对象,会造成500错误,鉴于此在feign-form项目中提了一个Issue(https://github.com/OpenFeign/feign-form/issues/19)
<!-- feign实现上传文件 -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.0.0</version>
</dependency>
修改配置Feign客户端
这里使用接口内部类方式,给接口扩展对文件的编写转换支持,这是java8的方式,java9接口又有增强。
- 必须在客户端接口配置consumes = MULTIPART_FORM_DATA_VALUE,否则MultipartFile实例无法被正常encode解析.
- 修改Encoder定义,需要通过构造函数载入当前定义的所有HttpMessageConverters
- @RequestParam,@RequestPart同样支持multipart/form-data请求
- @RequestParam适用于name-valueString类型的请求域,@RequestPart适用于复杂的请求域(像JSON,XML)。
@FeignClient(value = "service-producer", fallback = DevServiceFallback.class, configuration = {DevService.MultipartSupportConfig.class})
public interface DevService extends IDevService {
/**设备系统文件上传*/
@ApiOperation("设备系统文件上传")
@PostMapping(value = "/dev/reg/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ApiResult devFileUpload(@RequestPart("uploadFile") MultipartFile uploadFile,
@RequestParam(value = "name") String name,
@RequestParam(value = "type") String type,
@RequestParam(value = "desc", required = false) String desc,
@RequestParam(value = "version") String version);
@Configuration
class MultipartSupportConfig {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
@Primary
@Scope("prototype")
public Encoder feignEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}
}
@Requestboby功能验证
注意:下面包括三种参数:
- RequestBody - Json
- RequestParam - keyValue(string)
- PathVariable - {}
@RequestMapping(value = "/postBobyAParamAPathVar/{id}", method = RequestMethod.POST)
public String postBobyAParamAPathVar(
@RequestBody(required = true) Map<String, Object> map,
@RequestParam(value = "userName") String userName,
@PathVariable(value = "id") String id) {
ServiceInstance instance = client.getInstances("service1").get(0);
String retValue = map.get("username") + "(英文名:" + userName + ") ask that(id:" + id + "), host:" +
instance.getHost() + ";port:" + instance.getPort() + "; service_id:" + instance.getServiceId();
logger.info(retValue);
return retValue;
}
文件上传功能验证
- @RequestParam,@RequestPart同样支持multipart/form-data请求
- @RequestParam适用于name-valueString类型的请求域,@RequestPart适用于复杂的请求域(像JSON,XML)。
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody
String handleFileUpload(@RequestParam(value = "file", required = true) MultipartFile file,
@RequestParam(value = "name") String name) throws IOException {
byte[] bytes = file.getBytes();
File fileToSave = new File(file.getOriginalFilename());
FileCopyUtils.copy(bytes, fileToSave);
System.out.println(name);
return fileToSave.getAbsolutePath();
}
小结
在微服务中传递file, json, key-value(string)及路径{}等参数,其中file需要使用三方库feign-form。