SpringCloud + Nacos环境下抽取Feign独立模块并支持MultipartFile

一、前提条件和背景

1. 前提

已经部署好Nacos,本文以192.168.101.65:8848为例。

2. 背景

有两个微服务mediacontent,都已经注册到Nacos
后者通过引用Feign实现远程调用前者。
两个微服务都被分为3个子模块:api、service、model,对应三层架构。

请根据自身情况出发阅读本文。

二、Feign模块

1. 依赖引入

首先需要Feign依赖和扩展。

 <!--   openfeign     -->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-loadbalancer</artifactId>
     <version>4.1.0</version>
 </dependency>
 <dependency>
     <groupId>io.github.openfeign</groupId>
     <artifactId>feign-httpclient</artifactId>
 </dependency>
 <!--feign支持Multipart格式传参-->
 <dependency>
     <groupId>io.github.openfeign.form</groupId>
     <artifactId>feign-form</artifactId>
     <version>3.8.0</version>
 </dependency>
 <dependency>
     <groupId>io.github.openfeign.form</groupId>
     <artifactId>feign-form-spring</artifactId>
     <version>3.8.0</version>
 </dependency>

需要测试依赖(可选),为了MockMultipartFile类才引入的,非必需功能。

<!--    测试    -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>6.1.2</version>
	<scope>compile</scope>
</dependency>

其次需要涉及到的微服务的数据模型,根据个人情况而定。

如果只想要它们的数据模型,而不引入不必要的依赖,可以使用通配符*全部过滤掉。

 <!--   数据模型pojo     -->
 <dependency>
     <groupId>com.xuecheng</groupId>
     <artifactId>xuecheng-plus-media-model</artifactId>
     <version>0.0.1-SNAPSHOT</version>
	     <exclusions>
	          <exclusion>
	              <groupId>*</groupId>
	              <artifactId>*</artifactId>
	          </exclusion>
	      </exclusions>
 </dependency>
 <dependency>
     <groupId>com.xuecheng</groupId>
     <artifactId>xuecheng-plus-content-model</artifactId>
     <version>0.0.1-SNAPSHOT</version>
	     <exclusions>
	         <exclusion>
	             <groupId>*</groupId>
	             <artifactId>*</artifactId>
	         </exclusion>
	     </exclusions>
 </dependency>

2. application.yaml配置

填入以下内容,大抵为超时熔断处理。(可选),甚至可以留空。

feign:
  hystrix:
    enabled: true
  circuitbreaker:
    enabled: true
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000
ribbon:
  ConnectTimeout: 60000
  ReadTimeout: 60000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 1

3. 扩展支持MultipartFile

新建一个配置类,如下,
主要是Encoder feignEncoder()使得Feign支持MultipartFile类型传输。
MultipartFile getMultipartFile(File file)是一个工具方法,和配置无关。

@Configuration
public class MultipartSupportConfig {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    @Primary//注入相同类型的bean时优先使用
    @Scope("prototype")
    public Encoder feignEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    //将file转为Multipart
    public static MultipartFile getMultipartFile(File file) {
        try {
            byte[] content = Files.readAllBytes(file.toPath());
            MultipartFile multipartFile = new MockMultipartFile(file.getName(),
                    file.getName(), Files.probeContentType(file.toPath()), content);
            return multipartFile;
        } catch (IOException e) {
            e.printStackTrace();
            XueChengPlusException.cast("File->MultipartFile转化失败");
            return null;
        }
    }
}

4. 将media-api注册到feign

新建一个类,如下。
@FeignClient(value)要和服务名称对上,即media模块spring.application.name=media-api
@FeignClient(path)要和服务前缀路径对上,即media模块server.servlet.context-path=/media
然后MediaClient中的方法定义尽量和media模块对应的controller函数保持一致。

@FeignClient(value = "media-api", path = "/media")
public interface MediaClient {

    @RequestMapping(value = "/upload/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public UploadFileResultDto upload(
            @RequestPart("filedata") MultipartFile file,
            @RequestParam(value = "objectName", required = false) String objectName
    );
}

三、Media模块

被调用方media模块无需做什么修改。

四、Content模块

测试在content-api上操作。

1. 引入依赖

content模块需要引入刚才feign模块的依赖。

<dependency>
   <!-- 根据自身情况引入 -->
</dependency>

2. 启用FeignClient

在启动类上加上@EnableFeignClients注解。

3. 测试

新建测试类,如下

package com.xuecheng.content.service.jobhandler;

import com.xuecheng.feign.client.MediaClient;
import com.xuecheng.media.model.dto.UploadFileResultDto;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;

@SpringBootTest
class CoursePublishTaskTest {
    @Autowired
    MediaClient mediaClient;

    @Test
    void generateCourseHtml() {
        MultipartFile file = new MockMultipartFile(
                "filedata",
                "filename.txt",
                "text/plain",
                "Some dataset...".getBytes()
        );
        UploadFileResultDto upload = mediaClient.upload(file, "/static-test/t-1");
        System.out.println(upload);
    }
}

启动Media模块,启动测试方法,
具体的Debug和检验,可以通过Media模块对应的controller函数打印日志,检查是否通过MediaClient 被触发。

五、需要澄清的几点

  1. Feign模块不需要注册到Nacos且不需要服务发现
    正确。feign-client模块只是一个包含Feign客户端接口的库,它自身并不是一个独立的微服务。因此,它不需要注册到Nacos,也不需要服务发现功能。这个模块只是被其他微服务模块(如content模块)作为依赖引入。这样做的主要目的是为了代码的重用和解耦,允许任何微服务通过引入这个依赖来调用其他服务。

  2. 只有调用者(如content模块)需要使用@EnableFeignClients注解,被调用者(如media模块)不需要
    正确。@EnableFeignClients注解是用来启用Feign客户端的,它告诉Spring Cloud这个服务将会使用Feign来进行远程服务调用。因此,只有需要使用Feign客户端的服务(在这个例子中是content模块)需要添加这个注解。而被调用的服务(如media模块),只需作为普通的Spring Boot应用运行,提供REST API即可,无需使用@EnableFeignClients

  3. 如何在服务间共享数据模型(如DTOs)而不引入不必要的依赖。
    解决这个问题的一种方法是创建一个共享的库或模块,这个库包含所有服务共享的数据模型。另一种使用依赖剥离,使用通配符(*)可以排除pom.xml中特定依赖的所有传递性依赖。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值