SpringBoot 使用 Feign进行远程调用、文件上传等操作

JAVA 项目中接口调用怎么做?

1 Httpclient

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。

HttpClient 相比传统 JDK 自带的 URLConnection,提升了易用性和灵活性,使客户端发送 HTTP 请求变得容易,提高了开发的效率。

2. Okhttp

一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由 Square 公司贡献,用于替代 HttpUrlConnection 和 Apache HttpClient。OkHttp 拥有简洁的 API、高效的性能,并支持多种协议(HTTP/2 和 SPDY)。

3. HttpURLConnection

HttpURLConnection 是 Java 的标准类,它继承自 URLConnection,可用于向指定网站发送 GET 请求、POST 请求。HttpURLConnection 使用比较复杂,不像 HttpClient 那样容易使用。

4.RestTemplate

RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率。

5. Feign

Feign 是一个声明式的 REST 客户端,它能让 REST 调用更加简单。Feign 供了 HTTP 请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。

而 Feign 则会完全代理 HTTP 请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。

Spring Cloud 对 Feign 进行了封装,使其支持 SpringMVC 标准注解和 HttpMessageConverters。Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。

在Spring Boot 中集成Feign

1 引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>3.1.0</version>
</dependency>

2 通过@EnableFeignClients开启 feign 功能

@EnableFeignClients
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3 编写 feign接口进行远程调用

//${}可以应用application.yml内的配置,path会拼接到最后面
@FeignClient(value = "feignInterface",url="${test.url}/test",path = "/service",configuration = GlobalFeignConfig.class)
public interface FeignInterface {
	
    //请求 ${test.url}/test/service/hello 接口
    @GetMapping("/hello")
    public String getNameByParam( @RequestParam String userName );
}

Feign配置类

@FeignClient内的configuration可以对 feign请求进行先关配置

public class GlobalFeignConfig implements RequestInterceptor {


    @Bean
    public OkHttpInterceptor okHttpInterceptor() {
        return new OkHttpInterceptor();
    }

    @Bean
    public okhttp3.OkHttpClient okHttpClient() {
        return new okhttp3.OkHttpClient.Builder()
                .readTimeout(60, TimeUnit.SECONDS)
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(120, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool())
                .addInterceptor(okHttpInterceptor())
                .build();
    }

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    @Bean
    public Decoder feignDecoder() {
        return new ResponseEntityDecoder(new SpringDecoder(feignHttpMessageConverter()));
    }

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

    @Bean
    public ErrorDecoder errorDecoder() {
        return new ErrorDecoder.Default();
    }


    public ObjectFactory<HttpMessageConverters> feignHttpMessageConverter() {
        final HttpMessageConverters httpMessageConverters = new HttpMessageConverters(new PhpMappingJackson2HttpMessageConverter());
        return () -> httpMessageConverters;
    }

    class PhpMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
        PhpMappingJackson2HttpMessageConverter() {
            List<MediaType> mediaTypes = new ArrayList<>();
            mediaTypes.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8")); //关键
            setSupportedMediaTypes(mediaTypes);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            setObjectMapper(objectMapper);
        }
    }
    /**
     * 如果需要basic认证
     */
//    @Bean
//    public BasicAuthenticationInterceptor basicAuthenticationInterceptor(){
//        return new BasicAuthenticationInterceptor();
//    }
}

OkHttpInterceptor: 拦截器可以设置请求头等信息

@Slf4j
public class OkHttpInterceptor implements HandlerInterceptor, Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        log.debug("进入okhttp拦截器");
        Request request = chain.request();
        Request.Builder builder = request.newBuilder();

        //加上租户标识
        if(StrUtil.isNotBlank(SessionValueHolder.getCompanyCode())){
            builder.header(Constants.COMPANY_CODE, SessionValueHolder.getCompanyCode());
        }
        //加上token
        if(StrUtil.isNotBlank(SessionValueHolder.getAuthorization())){
            builder.header(Constants.AUTHORIZATION_KEY, SessionValueHolder.getAuthorization());
        }
        //加上feign调用标识
        builder.header(Constants.FEGIN_FLAG, "1");

        return chain.proceed(builder.build());
    }
}

feign 配置文件相关配置

# 链接超时时间 feignName写自己feign接口的类名
feign.client.config.feignName.connectTimeout=5000
# 读取超时时间
feign.client.config.feignName.readTimeout=5000
# 日志等级
feign.client.config.feignName.loggerLevel=full
# 重试
feign.client.config.feignName.retryer=com.example.SimpleRetryer
# 拦截器
feign.client.config.feignName.requestInterceptors[0]=com.example.FooRequestInterceptor
feign.client.config.feignName.requestInterceptors[1]=com.example.BarRequestInterceptor
# 编码器
feign.client.config.feignName.encoder=com.example.SimpleEncoder
# 解码器
feign.client.config.feignName.decoder=com.example.SimpleDecoder
# 契约
feign.client.config.feignName.contract=com.example.SimpleContract

#开启GZIP压缩,请求数据量很大的接口提高性能
#对请求数据进行压缩
feign.compression.request.enabled=true
#对响应数据进行压缩
feign.compression.response.enabled=true
#指定 请求方式 进行压缩
feign.compression.request.mime-types=text/xml,application/xml,application/json
#设置最小压缩大小,只有超过了这个大小才会进行压缩
feign.compression.request.min-request-size=2048

实战练习

通过Feign调用我们实现申明的接口进行测试:

Controller

@RestController
@RequestMapping("service")
public class ServiceController {

	//请求参数
    @GetMapping("/param")
    public String getNameByParam( String userName ){
        return userName;
    }

    //请求体
    @PostMapping("/body")
    public String getNameByBody( @RequestBody String userName ){
        return userName;
    }

    @GetMapping("/timeout/5000")
    public String timeout( @RequestParam(required = false,defaultValue = "5000") long millis ) throws Exception {
        Thread.sleep( millis );
        return "success";
    }

    //单文件
    @PostMapping(value = "/file",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String file(@RequestPart("file2") MultipartFile multipartFile){
        if( multipartFile == null ) return null;
        return multipartFile.getName();
    }

    //多文件
    @PostMapping("/files")
    public Iterable<String> files(MultipartRequest multipartRequest){
        if( multipartRequest == null ) return null;


        List<String> fileNameArray = new ArrayList();


        if( multipartRequest instanceof  StandardMultipartHttpServletRequest){
            StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) multipartRequest;

            List<String> fileNameList = request.getMultiFileMap().values().stream()
                    .flatMap(o -> o.stream())
                    .map( MultipartFile::getOriginalFilename ).collect(Collectors.toList());
            return fileNameList;
        }

        Iterator<String> fileNames = multipartRequest.getFileNames();

        while(fileNames.hasNext()){
            String fileName = fileNames.next();
            fileNameArray.add( multipartRequest.getFile(fileName).getOriginalFilename() );
        }

        return fileNameArray;
    }

}

Get请求传递参数

@GetMapping("/param")
public String getNameByParam( @RequestParam String userName );

Post请求传递请求头

@PostMapping("/body")
public String getNameByBody( @RequestBody String userName );

路径参数

@GetMapping("/timeout/{millis}")
public String timeout( @PathVariable long millis );

文件上传

//必须设置MediaType.MULTIPART_FORM_DATA_VALUE  使用 @RequestPart接收form格式的文件数据
@PostMapping(value="/file",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String file(@RequestPart("file2") MultipartFile multipartFile);

多文件上传

@PostMapping(value="/files",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Iterable<String> files( @RequestPart("file2") Collection<MultipartFile>  file);
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot Feign是一种用于远程调用的工具,它可以帮助开发者轻松地实现微服务之间的调用。通过Feign,开发者可以定义一个接口,然后在该接口上添加注解来指定调用的服务和方法。Feign会自动生成一个代理对象,开发者可以直接调用该代理对象的方法来实现远程调用Feign还提供了负载均衡和断路器等功能,可以帮助开发者更好地管理微服务之间的调用。 ### 回答2: SpringBoot Feign是一个基于HTTP请求的RESTful API客户端,它使得我们可以轻松地调用远程HTTP服务,而无需编写复杂的代码和配置。它通过在接口层面声明HTTP请求的方式,将HTTP请求以类和方法的形式组织,并且支持负载均衡、服务发现和请求过滤功能。 在使用SpringBoot Feign进行远程调用时,需要依赖Feign的starter和Eureka的starter。在启动类上使用@EnableFeignClients注解启用Feign客户端,并在需要使用接口上添加@FeignClient注解,同时可以在注解中指定要访问的远程服务的名称,即Spring Cloud中注册到Eureka注册中心的服务名。 Feign客户端通过动态代理将接口中的请求映射到目标URI中,并发送对应的HTTP请求,接收响应并返回。请求的参数和返回的内容均可以使用注解进行控制。此外,Feign还支持多种请求方式(GET、POST、DELETE、PUT等),以及请求头、请求体的自定义。 对于负载均衡,Feign默认集成了Ribbon实现客户端负载均衡。通过在注解中指定服务名,Feign会自动调用Ribbon进行负载均衡处理,以便访问多个提供同一服务的实例机器。对于服务发现,Feign同样与Eureka无缝集成,可以通过注解指定服务名来自动完成服务发现操作。 在调用远程服务的过程中,Feign还支持请求的重试机制和请求过滤器,可以通过实现RequestInterceptor接口来定义请求拦截器,实现Fallback接口来定义请求失败后的处理方法。 总之,SpringBoot Feign使得我们可以以非常简单和便捷的方式调用远程HTTP服务,并且在实现服务注册、发现、负载均衡等方面无需太多配置和复杂的代码,极大地提高了系统的性能和扩展性。 ### 回答3: Spring Boot Feign是一个基于HTTP的RESTful API客户端,可以在Spring应用中使用。 它可以帮助开发人员从应用程序中轻松地调用远程服务。 Spring Boot Feign的主要功能包括: 1. 通过在接口使用注解,使用简单易用的声明式RESTAPI调用。 2. 提供了非常简单的编程方式,而无需手动处理HTTP请求。 3. 支持Apache HttpClient和OkHttp等多个HTTP客户端。 4. 可以基于已有的Ribbon负载均衡器,实现远程服务的自动负载均衡。 5. 支持请求和响应的压缩。 6. 支持异步调用。 使用Spring Boot Feign进行远程调用步骤如下: 1. 添加Spring Boot Feign依赖。 2. 定义Feign客户端接口,该接口包含声明要访问的远程服务的所有方法。 3. 添加Feign客户端接口的注释,以标识所需的远程服务。 4. 创建Feign客户端。 5. 使用Feign客户端来调用定义的方法,以访问远程服务。 作为一个开发人员,需要对Feign客户端接口进行声明,以定义将要访问的远程服务。通过使用注释,我们可以声明需要访问哪个服务和使用哪个URL。Spring Boot Feign可以自动处理HTTP请求,从而允许简单和干净的代码,而无需手动处理HTTP头/正文。使用Feign客户端接口定义的方法,可以像本地方法一样使用,但实际上它们将向远程服务器发出请求使用Spring Boot Feign进行远程调用的好处是: 1. 代码简单,易于理解。 2. 降低了与远程服务交互的复杂性。 3. 可以节省调用远程服务的成本和时间。 4. 帮助开发人员更快地进行开发和测试。 总之,Spring Boot Feign是一种非常强大的框架,可以帮助开发人员更轻松地进行RESTful API的开发和调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值