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

文章目录

  • 一、前提条件和背景
      • 1. 前提
      • 2. 背景
  • 二、Feign模块
      • 1. 依赖引入
      • 2. `application.yaml`配置
      • 3. 扩展支持MultipartFile
      • 4. 将media-api注册到feign
  • 三、Media模块
  • 四、Content模块
      • 1. 引入依赖
      • 2. 启用FeignClient
      • 3. 测试
  • 五、需要澄清的几点

一、前提条件和背景

1. 前提

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

2. 背景

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

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

二、Feign模块

1. 依赖引入

首先需要Feign依赖和扩展。

 
 <dependency>
     <groupId>org.springframework.cloudgroupId>
     <artifactId>spring-cloud-starter-openfeignartifactId>
 dependency>
 <dependency>
     <groupId>org.springframework.cloudgroupId>
     <artifactId>spring-cloud-starter-loadbalancerartifactId>
     <version>4.1.0version>
 dependency>
 <dependency>
     <groupId>io.github.openfeigngroupId>
     <artifactId>feign-httpclientartifactId>
 dependency>
 
 <dependency>
     <groupId>io.github.openfeign.formgroupId>
     <artifactId>feign-formartifactId>
     <version>3.8.0version>
 dependency>
 <dependency>
     <groupId>io.github.openfeign.formgroupId>
     <artifactId>feign-form-springartifactId>
     <version>3.8.0version>
 dependency>

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


<dependency>
	<groupId>org.springframeworkgroupId>
	<artifactId>spring-testartifactId>
	<version>6.1.2version>
	<scope>compilescope>
dependency>

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

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

 
 <dependency>
     <groupId>com.xuechenggroupId>
     <artifactId>xuecheng-plus-media-modelartifactId>
     <version>0.0.1-SNAPSHOTversion>
	     <exclusions>
	          <exclusion>
	              <groupId>*groupId>
	              <artifactId>*artifactId>
	          exclusion>
	      exclusions>
 dependency>
 <dependency>
     <groupId>com.xuechenggroupId>
     <artifactId>xuecheng-plus-content-modelartifactId>
     <version>0.0.1-SNAPSHOTversion>
	     <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中特定依赖的所有传递性依赖。

你可能感兴趣的:(SpringCloud,#,OpenFeign,spring,cloud,spring,后端)