栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

@FeignClient 上传文件时报错 解决方案

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

@FeignClient 上传文件时报错 解决方案

Feign 作为 Spring Cloud 中 RPC 工具,利用注解来描述接口,简化了 Java HTTP Client 的调用过程。但是在文件上传时,我们需要做一些额外的配置,不然会调用异常。

背景

我有一个服务 A,里面有个接口,需要接受上传的文件和一些参数,

 @PostMapping({"/validityPeriod/update"})
    BizResponse proofValidityPeriodUpdate(@Validated ValidityPeriodUpdateRequest request);

其中 ValidityPeriodUpdateRequest 代码如下:

public class ValidityPeriodUpdateRequest {
    @NotEmpty(
        message = "操作名称 不能为空"
    )
    @ApiModelProperty("操作名称")
    private String operateName;
    @ApiModelProperty("延期时间,如: 2025-01-01")
    private String delayDate;
    @ApiModelProperty("延期天数")
    private Integer delayDays;
    @ApiModelProperty("延期数据, Excel 文件")
    private MultipartFile delayData;
    @ApiModelProperty("备注")
    private String remark;
    @NotEmpty(
        message = "操作人不能为空"
    )
    @ApiModelProperty("操作人")
    private String operator;

注意,private MultipartFile delayData; 接受一个文件。

然后服务B 作为一个 BFF,回去调用 服务 A 的 这个接口,

使用默认的 Feign 配置去调用的话

@FeignClient(name = "ext-website-mkt-coupon-setting")
public interface CouponOperateTaskClient extends CouponOperateTaskService {
}

会报如下异常:

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class java.io.FileDescriptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.tuhu.mkt.coupon.api.dto.operate.request.ValidityPeriodUpdateRequest["delayData"]->org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile["inputStream"]->java.io.FileInputStream["fd"])

google 一下发现, openfign 不支持 参数中带文件。

解决方案

OpenFeign 默认不支持文件参数,但提供了 feign-form 拓展工具。

查看官网介绍,大致意思如下:

feign-form 扩展依赖于 open-feign 的特定版本

open-feign 9.* 版本对应使用 feign-from 3.5.0 之前的版本

open-feign 10.1.0 以及以后的版本对应使用 3.5.0 以及以后版本

feign-from 3.5.0 之后的版本没有兼容 open-feign 10.* 之前的版本,10版本的 open-feign 重构了代码,所以最好的方法是用最新的版本

spring-cloud-openfeign:2.0.3.release 之前用 open-feign 9. 版本,2.0.3.release 之后的版本用 open-feign 10.*, 且在 2.0.3.release 之后的版本里面已经包含 feign-form 的依赖,不需要再去指定相应的版本*

spring-cloud-starter-feign 已经不推荐使用,他依赖的依然是 open-feign 9.*

好了看完 github 上的介绍,又看了下项目的 springcloud 版本 ,该版本不包含 feign-form 的依赖,需要我们手动引入 feign-from 3.5.0 之前的版本 版本。

添加 maven 依赖:

		
			io.github.openfeign.form
			feign-form
			3.4.1
		
		
			io.github.openfeign.form
			feign-form-spring
			3.4.1
		

引入完依赖后还需要编写配置类:

@Configuration
public class FeignSupportConfig {
    @Autowired
    private ObjectFactory messageConverters;

    @Bean
    @Primary
    @Scope("prototype")
    public Encoder feignEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

编写完 feign-form 的配置类后,还需要在 @FeignClient 注解中引入

@FeignClient(name = "ext-website-mkt-coupon-setting", configuration = FeignSupportConfig.class)
public interface CouponOperateTaskClient extends CouponOperateTaskService {
}

做完上面配置后,我们的代码写法也需要改动,
原来的接口定义:

 @PostMapping({"/validityPeriod/update"})
    BizResponse proofValidityPeriodUpdate(@Validated ValidityPeriodUpdateRequest request);

openfeign 也是不支持这样的类作为参数绑定的,需要结合 @RequestPart 注解 和 @RequestParam 注解,共同完成参数的绑定:

@PostMapping(value = "/validityPeriod/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    BizResponse proofValidityPeriodUpdate(@RequestPart("delayData") MultipartFile delayData,
                                           @RequestParam("operateName") String operateName,
                                           @RequestParam(name = "delayDate",required = false) String delayDate,
                                           @RequestParam(name = "delayDays",required = false) Integer delayDays,
                                           @RequestParam("remark") String remark,
                                           @RequestParam("operator") String operator
    );

注意,不要忘记加上 consumes = MediaType.MULTIPART_FORM_DATA_VALUE 配置。

这样配置完之后,我们就再来测试下

完美解决问题。

总结

后面可以考虑升级 springcloud 版本来解决此问题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/749673.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号