@FeignClient upload file error solution

As an RPC tool in Spring Cloud, Feign uses annotations to describe interfaces, which simplifies the calling process of Java HTTP Client. But when uploading files, we need to do some additional configuration, otherwise an exception will be called.

background

I have a service A with an interface that needs to accept uploaded files and some parameters,

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

The ValidityPeriodUpdateRequest code is as follows:

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;

Note that private MultipartFile delayData;a file is accepted.

Then service B, as a BFF, goes back to call this interface of service A,

If you use the default Feign configuration to call

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

The following exception will be reported:

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 found that openfign does not support files in parameters.

solution

OpenFeign does not support file parameters by default, but provides feign-form extension tools.

View the official website introduction, the general meaning is as follows:

The feign-form extension depends on a specific version of open-feign

The open-feign 9.* version corresponds to the version before feign-from 3.5.0

Open-feign 10.1.0 and later versions correspond to 3.5.0 and later versions

Versions after feign-from 3.5.0 are not compatible with versions prior to open-feign 10.*, version 10 of open-feign has refactored the code, so the best way is to use the latest version

spring-cloud-openfeign: Before 2.0.3.release, open-feign 9. version is used, after 2.0.3.release, open-feign 10.* is used, and feign is already included in the version after 2.0.3.release -form dependency, no need to specify the corresponding version *

spring-cloud-starter-feign is no longer recommended, it still relies on open-feign 9.*

Well, after reading the introduction on github, I also looked at the springcloud version of the project. This version does not contain the dependency of feign-form, so we need to manually introduce the version before feign-from 3.5.0.

Add maven dependency:

		<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>

After introducing dependencies, you need to write configuration classes:

@Configuration
public class FeignSupportConfig {
    
    
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

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

After writing the feign-form configuration class, you also need to introduce it in the @FeignClient annotation

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

After completing the above configuration, our code writing method also needs to be changed.
The original interface definition:

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

Openfeign also does not support such classes as parameter binding, and needs to combine @RequestPartannotations and @RequestParamannotations to complete the parameter binding:

@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
    );

Note, don't forget to add consumes = MediaType.MULTIPART_FORM_DATA_VALUEconfiguration.

After this configuration is complete, let's test it again.

Solve the problem perfectly.

Summarize

Later, you can consider upgrading the springcloud version to solve this problem.

Guess you like

Origin blog.csdn.net/itguangit/article/details/123187027