驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
Spring Cloud Feign 复杂用法:文件上传+复杂参数传递【官方方案】
/  

Spring Cloud Feign 复杂用法:文件上传+复杂参数传递【官方方案】

开篇

Feign在Github上开源了一个项目,可以更加方便的利用Feign进行文件传输和多参数传输。

项目地址:https://github.com/OpenFeign/feign-form

这篇文章就结合官方的Test总结下用法。

使用前我们下载pom中引入相关包,其中核心的部分如下所示:

        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>xxx</version>
        </dependency>

        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form-spring</artifactId>
            <version>xxx</version>
        </dependency>

最新的版本,大家自己从:http://mvnrepository.com/ 检索吧!

文件上传

服务提供方

在web层的核心代码如下所示:

@RestController
public class Server {
    // MultipartFile必须使用 @RequestPart 进行修饰
    // consume为: MULTIPART_FORM_DATA_VALUE,表明只接收FormData这个类型的数据
    @RequestMapping(
            value = "/multipart/upload1/{folder}",
            method = POST,
            consumes = MULTIPART_FORM_DATA_VALUE)
    public String upload1(@PathVariable("folder") String folder,
                          @RequestPart MultipartFile file,
                          @RequestParam(value = "message", required = false) String message) {
        return new String(file.getBytes()) + ':' + message + ':' + folder;
    }
    

该代码中有需要注意:

  1. 必须是Post类型的请求。

  2. 文件形参必须用@RequestPara MultipartFile file来修饰,其中 @RequestParatMultipartFile必不可少。

  3. 形参中有3类参数,实际开发中可以改为对文件的描述信息

    • PathVariable 是在URL占位中的参数
    • RequestPart 是修改文件的参数
    • RequestParam 是URL中?后面的参数。

服务调用方Feign接口

@FeignClient(
        name = "multipart-support-service",
        url = "http://localhost:8080",
        configuration = Client.ClientConfiguration.class
)
public interface Client {

    //处理多个参数的时候,必须指定:consumes = MULTIPART_FORM_DATA_VALUE
    @RequestMapping(
            value = "/multipart/upload1/{folder}",
            method = POST,
            consumes = MULTIPART_FORM_DATA_VALUE
    )
    String upload1(@PathVariable("folder") String folder,
                   @RequestPart MultipartFile file,
                   @RequestParam(value = "message", required = false) String message);

    /**
     * 配置类
     */
    class ClientConfiguration {

        /**
         * 此处注入的是: ObjectFactory<HttpMessageConverters>
         */
        @Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;

        @Bean
        public Encoder feignEncoder() {
            return new SpringFormEncoder(new SpringEncoder(messageConverters));
        }
    }
}

方法中需要注意几个细节:

  1. FeignClient中的描述信息中,指定了配置信息为: Client.ClientConfiguration
  2. 请求参数形参注意事项同上所示,此处不再赘述。

我们来看看配置信息:

    /**
     * 配置类
     */
    class ClientConfiguration {

        /**
         * 此处注入的是: ObjectFactory<HttpMessageConverters>
         */
        @Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;

        @Bean
        public Encoder feignEncoder() {
            return new SpringFormEncoder(new SpringEncoder(messageConverters));
        }
    }

这部分代码表述的就是:获取已有的HttpMessageConvert然后将其包裹下,外层增加自己的编码器SpringFormEncoder。该写法是针对某个Feign Client的配置。

如果你的客户端所有的都需要这个配置,那么请通过如下方式配置:

@Configuration
public class MultipartSupportConfig {
    
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    
    @Bean
    @Primary
    @Scope("prototype")
    public Encoder feignEncoder() {
          return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
}

该配置中也是细节满满:

  1. 通过@Primary修饰,优先注入我们声明的。
  2. 通过 @Scope("prototype")每次使用都构建一个。

思考下为什么不做为单例了?

这样客户端调用的时候就成了,很简单吧!

复杂参数传递

实际开发中,我们可能会通过多种方式进行传输传递,这里就构建一个非常复杂的方式,服务提供方web层接口如下:

@RestController
public class Server {
  
    @RequestMapping(path = "/multipart/upload4/{id}",
            method = POST)
    public String upload4(@PathVariable("id") String id,
                          @RequestBody Map<String, Object> map,
                          @RequestParam String userName) {
        return userName + ':' + id + ':' + map.size();
    }
}

这个接口中包含了3类参数:

  1. @PathVariable

  2. @RequestBody

  3. @RequestParam

Feign的客户端接口如何写了?

@FeignClient(
        name = "multipart-support-service",
        url = "http://localhost:8080",
        configuration = Client.ClientConfiguration.class
)
public interface Client {

    // 传输的不是文件
    // 因为传输的参数有个map所以必须指定类型为 json
    // 经过测试发现:注释 produces = APPLICATION_JSON_VALUE 是没有问题的
    @RequestMapping(
            path = "/multipart/upload4/{id}",
            method = POST,
            produces = APPLICATION_JSON_VALUE
    )
    String upload4(@PathVariable("id") String id,
                   @RequestBody Map<Object, Object> map,
                   @RequestParam("userName") String userName);

    /**
     * 配置类,同上
     */
    class ClientConfiguration {

        /**
         * 此处注入的是: ObjectFactory<HttpMessageConverters>
         */
        @Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;

        @Bean
        public Encoder feignEncoder() {
            return new SpringFormEncoder(new SpringEncoder(messageConverters));
        }
    }
}

只需要包裹下编码器即可,很简单吧!

总结

上述用法都是来自:https://github.com/OpenFeign/feign-form 这个官方的pom中。

更多用法,可以参考这个pom中的Test。

积土成山,风雨兴焉。积水成渊,蛟龙生焉。