spring cloud feign 上传文件和下载文件

spring cloud feign 上传文件和下载文件

原文地址

什么是Feign

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

如何使用:

pom引入 Feign

<!--https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

注解

@FeignClient(name = "suibian",url = "${suibian.request.url}", configuration = FeignClientConfiguration.class)
  • name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现

  • url: url一般用于调试,可以手动指定@FeignClient调用的地址

  • decode404: 当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException

  • configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract

  • fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口

  • fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码

  • path: 定义当前FeignClient的统一前缀

配置类

Spring Cloud creates a new ensemble as an ApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

自带:FeignClientConfiguration.class,包含 feign.Decoder, feign.Encoder, feign.Contract

@Configuration
public class FeignFileUploadConfig {

  @Autowired
  private ObjectFactory<HttpMessageConverters> messageConverters;

  @Bean
  public Encoder feignFormEncoder() {
    return new SpringFormEncoder(new SpringEncoder(messageConverters));
  }
}
  • 添加Feign配置类,可以添加在主类下,但是不用添加@Configuration。
  • 如果添加了@Configuration而且又放在了主类之下,它将成为feign.Decoder,feign.Encoder,feign.Contract等的默认来源。那么就会所有Feign客户端实例共享,同Ribbon配置类一样父子上下文加载冲突。
  • 如果一定添加@Configuration,就放在主类加载之外的包。也可以在@ComponentScan中将其明确排除在外。
  • 建议还是不用加@Configuration。

添加日志级别

代码实现 && 配置实现

//写configuration类
public class FeignConfig {
    @Bean
    public Logger.Level Logger() {
        return Logger.Level.FULL;
    }
}
//写配置
logging:
  level:
    com.xxx.xxx.FeignAPI: DEBUG #需要将FeignClient接口全路径写上# 开启日志 格式为logging.level.+Feign客户端路径
feign:
  client:
    config:
      #想要调用的微服务名称
      server-1:
        loggerLevel: FULL

上传文件

消费服务: client代码分为controller层 remote调用接口

提供服务: server代码展示controller层

import

spring-cloud-starter-openfeign不支持文件上传,需要引入拓展的第三方包

 <!-- feign file upload-->
    <dependency>
      <groupId>io.github.openfeign.form</groupId>
      <artifactId>feign-form</artifactId>
      <version>3.3.0</version>
    </dependency>
    <dependency>
      <groupId>io.github.openfeign.form</groupId>
      <artifactId>feign-form-spring</artifactId>
      <version>3.3.0</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

代码实现

注意使用@RequestPart , 和 @RequestParam 最大的不同是,当请求方法的请求参数类型不再是String类型的时候,@RequestParam依赖于注册Converter或者PropertyEditor来解析参数,而 @RequestPart则是通过HttpMessageConverter来根据Content-Type决定采用的消息转换器。

@RequestParam适用于name-valueString类型的请求域,@RequestPart适用于复杂的请求域(像JSON,XML)。

服务消费方client的controller

@RequestMapping(value = "/upload", method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result upload(
    @RequestParam("id") Integer id,
    @RequestPart("file") MultipartFile multipartFile) {
    return fileClient.uplaod(id,multipartFile);
}

服务消费方client的feignclient

@FeignClient(name = "suibian",configuration = FeignFileUploadConfig.class)
public interface FileClient {
    @RequestMapping(value = "/upload", method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    Result upload(@RequestParam("id") Integer id,
                        @RequestPart("file") MultipartFile file);
}

FeignFileUploadConfig.class

//方法一
@Configuration
public class FeignFileUploadConfig {

  @Autowired
  private ObjectFactory<HttpMessageConverters> messageConverters;

  @Bean
  public Encoder feignFormEncoder() {
    return new SpringFormEncoder(new SpringEncoder(messageConverters));
  }
}
//方法二
@Configuration
public class FeignFileUploadConfig {

  @Bean
  public Encoder feignFormEncoder() {
    return new SpringFormEncoder();
  }
}

Tips:该方法不支持MultipartFile[] files因为第三方的拓展中,源码并没有对MultipartFile[] 这种情况进行处理。如果用这个类型的入参,请参考Spring Cloud feign 多文件上传

服务提供的controller

@RequestMapping(value = "/upload", method = RequestMethod.POST,consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result upload(@RequestParam("id") Integer id, @RequestPart("file") MultipartFile multipartFile) {
    String name = file.getOriginalFilename();
    System.out.println(name);
    File file1 = new File(imageFile.getOriginalFilename());
    file.transferTo(file1);
}

实际使用中发现, 在feignclient的@RequestPart(“file”) 指定的文件的key(file)好像不生效, 在服务提供方的controller的@RequestPart(“file”)应该和服务消费方的controller的@RequestPart(“file”)保持一直

下载文件

消费服务: client代码分为controller feignclient

提供服务: server代码展示controller

服务消费方client 的 controller

@RequestMapping(value = "/xxxx",method = RequestMethod.GET)
public void getImagesById(@RequestParam("id") Integer id, HttpServletResponse response){
    InputStream inputStream = null;
    OutputStream outputStream=null;
    try {
        // feign文件下载
        Response responseFromRemote = fileClient.getFile(id);
        Response.Body body = responseFromRemote.body();
        inputStream = body.asInputStream();
        outputStream = response.getOutputStream();
        // byte[] b = new byte[inputStream.available()];
        byte[] buffer = new byte[1024 * 8];
        int count = 0;
        while ((count = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, count);
        }
        outputStream.flush();

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务消费方的feignclient

@RequestMapping(value = "/xxxx/{id}",method = RequestMethod.GET)
Response getFile(@PathVariable("id") Integer id);

注意这里的包是feign.Response=

服务提供方的 controller

@RequestMapping(value = "/xx/{id}",method = RequestMethod.GET)
public void getFile(@PathVariable("id") Integer id, HttpServletResponse response) {
    InputStream is = null;
    OutputStream os = null;
    try {
        //本地文件
		is = new FileInputStream(new File(""));
        os = response.getOutputStream();
        int count = 0;
        byte[] buffer = new byte[1024 * 8];
        while ((count = fis.read(buffer)) != -1) {
            os.write(buffer, 0, count);
        }
        os.flush();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            fis.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }j
}

参考资料链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值