1、接上一篇文件上传
本来文件上传的代码比较简单,我在springboot2 + springcloud2 (spring-cloud-starter-openfeign版本:2.2.5.RELEASE)的时候,一次成功,
但是在sprinboot1 + springcloud1(spring-cloud-starter-feign版本:1.4.7.RELEASE),我无论怎么尝试都没有办法实现文件上传,我到官方上查了一下,发现新版本的feign-form废弃了spring-cloud-starter-feign,我一度以为在1.x版本上feign是没有办法实现文件上传的。
后来查了很多资料,发现肯定是可以,无非还是重写SpringFormEncoder,那重写的话就是使用feign-form
我被逼的没办法,我创建了一个干净的工程,只为了尝试文件上传,发现尽然成功了。到这里我才突然发现,我查问题的思路错了。文件上传本身代码没有问题。我开始找到旧的工程开始添加依赖包。终于让我发现了问题
还是说一下我项目的特殊性在哪里
(1)我这个项目是进行了一些工具类的封装,具体包括钉钉api对接,发邮件,发短信,快递。目的是减少其他项目的代码,并且对其他的项目隐藏配置(比如各种第三方服务的appkey和app
发送邮件服务
@ConditionalOnClass(FeignClient.class)
@FeignClient(value = "openservice", configuration = OpenServiceMailFeignService.MultipartSupportConfig.class)
@RequestMapping("/srv010600601/v0.0.1")
public interface OpenServiceMailFeignService {
}
发现问题了没有,两个服务的@FeignClient配置的value都是"openservice"。这个开始肯定的,因为服务端是一个。
我的测试工程代码在单独引用以上两个包的时候,自然是没有问题,各种好使,问题就出来我两个包全部引用的使用。邮件服务的configuration不好使了 ,文件上传怎么都不行。
在feign1.x版本的时候,是区别不出来客户端的。对比之下,openfeign2.x版本,添加了一个contextId属性,就解决了这个问题。所以在openfeign2.x版本的时候,是不用这么费事的设置的。
回到我们的问题,因为两个多个feignclient重名的时候,区分不出来,则feignclient就存在configuration被覆盖的情况。按照加载顺序来的。
我尝试过控制这几个feignclient的加载顺序,但是没找到相关的配置,这个思路作罢
然后找到了这篇文章
spring cloud 两个feignclient 名称相同时的问题
我按照里面的配置试了一下,是没问题的
这里把代码贴出来,
第一个方法:在配置类上添加@Component
但是需要注意的是,我试验的结果是,只能是内部类。在openfeign2.x的时候,内部类和外部类随便用。
@ConditionalOnClass(FeignClient.class)
@FeignClient(value = "openservice", configuration = OpenServiceMailFeignService.MultipartSupportConfig.class)
@RequestMapping("/srv010600601/v0.0.1")
public interface OpenServiceMailFeignService {
@PostMapping(value = "/sendMail", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
@ResponseBody
boolean sendMail(@RequestParam("to") String to,
@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam(value = "attachmentName",required = false) String attachmentName,
@RequestPart(value = "attachmentFile",required = false) MultipartFile attachmentFile);
/**
* feignclient为了支持文件上传,需要配置SpringFormEncoder
* 其中的@Component注解是为了在多个同名feignclient时configuration不产生覆盖
*/
@Component
class MultipartSupportConfig {
@Bean("multipartFormEncoder")
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() throws BeansException {
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
}
}));
}
@Bean("multipartLoggerLevel")
public feign.Logger.Level multipartLoggerLevel() {
return feign.Logger.Level.FULL;
}
}
}
第二个方法是
将feign的名称添加上http:// ,这个时候不需要@Component注解
@ConditionalOnClass(FeignClient.class)
@FeignClient(value = "http://openservice", configuration = OpenServiceMailFeignService.MultipartSupportConfig.class)
@RequestMapping("/srv010600601/v0.0.1")
public interface OpenServiceMailFeignService {
@PostMapping(value = "/sendMail", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
@ResponseBody
boolean sendMail(@RequestParam("to") String to,
@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam(value = "attachmentName",required = false) String attachmentName,
@RequestPart(value = "attachmentFile",required = false) MultipartFile attachmentFile);
/**
* feignclient为了支持文件上传,需要配置SpringFormEncoder
*/
class MultipartSupportConfig {
@Bean("multipartFormEncoder")
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(new ObjectFactory<HttpMessageConverters>() {
@Override
public HttpMessageConverters getObject() throws BeansException {
return new HttpMessageConverters(new RestTemplate().getMessageConverters());
}
}));
}
@Bean("multipartLoggerLevel")
public feign.Logger.Level multipartLoggerLevel() {
return feign.Logger.Level.FULL;
}
}
}
最后特别添加
因为这个问题,看了github的Issues问题解答,发现原来openfeign中,@的contextId这个属性就是因为解决重名问题而产生的。(*^▽^*)
建议看一下
Support different custom configurations for multiple feign clients with the same name #1211
Support different custom configurations for multiple feign clients with the same name #67