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

2022年12月2日08:59:12

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@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[] args){SpringApplication.run(Application.class, args);}}

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

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

Feign配置类

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

publicclassGlobalFeignConfigimplementsRequestInterceptor{@BeanpublicOkHttpInterceptorokHttpInterceptor(){returnnewOkHttpInterceptor();}@Beanpublicokhttp3.OkHttpClientokHttpClient(){returnnewokhttp3.OkHttpClient.Builder().readTimeout(60,TimeUnit.SECONDS).connectTimeout(60,TimeUnit.SECONDS).writeTimeout(120,TimeUnit.SECONDS).connectionPool(newConnectionPool()).addInterceptor(okHttpInterceptor()).build();}@BeanLogger.LevelfeignLoggerLevel(){returnLogger.Level.FULL;}@BeanpublicDecoderfeignDecoder(){returnnewResponseEntityDecoder(newSpringDecoder(feignHttpMessageConverter()));}@BeanpublicEncoderfeignEncoder(){returnnewSpringEncoder(feignHttpMessageConverter());}@BeanpublicErrorDecodererrorDecoder(){returnnewErrorDecoder.Default();}publicObjectFactory<HttpMessageConverters>feignHttpMessageConverter(){finalHttpMessageConverters httpMessageConverters=newHttpMessageConverters(newPhpMappingJackson2HttpMessageConverter());return()-> httpMessageConverters;}classPhpMappingJackson2HttpMessageConverterextendsMappingJackson2HttpMessageConverter{PhpMappingJackson2HttpMessageConverter(){List<MediaType> mediaTypes=newArrayList<>();
            mediaTypes.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE+";charset=UTF-8"));//关键setSupportedMediaTypes(mediaTypes);ObjectMapper objectMapper=newObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            objectMapper.setDateFormat(newSimpleDateFormat("yyyy-MM-dd HH:mm:ss"));setObjectMapper(objectMapper);}}/**
     * 如果需要basic认证
     *///    @Bean//    public BasicAuthenticationInterceptor basicAuthenticationInterceptor(){//        return new BasicAuthenticationInterceptor();//    }}

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

@Slf4jpublicclassOkHttpInterceptorimplementsHandlerInterceptor,Interceptor{@OverridepublicResponseintercept(Chain chain)throwsIOException{
        log.debug("进入okhttp拦截器");Request request= chain.request();Request.Builder builder= request.newBuilder();//加上租户标识if(StrUtil.isNotBlank(SessionValueHolder.getCompanyCode())){
            builder.header(Constants.COMPANY_CODE,SessionValueHolder.getCompanyCode());}//加上tokenif(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")publicclassServiceController{//请求参数@GetMapping("/param")publicStringgetNameByParam(String userName){return userName;}//请求体@PostMapping("/body")publicStringgetNameByBody(@RequestBodyString userName){return userName;}@GetMapping("/timeout/5000")publicStringtimeout(@RequestParam(required=false,defaultValue="5000")long millis)throwsException{Thread.sleep( millis);return"success";}//单文件@PostMapping(value="/file",consumes=MediaType.MULTIPART_FORM_DATA_VALUE)publicStringfile(@RequestPart("file2")MultipartFile multipartFile){if( multipartFile==null)returnnull;return multipartFile.getName();}//多文件@PostMapping("/files")publicIterable<String>files(MultipartRequest multipartRequest){if( multipartRequest==null)returnnull;List<String> fileNameArray=newArrayList();if( multipartRequestinstanceofStandardMultipartHttpServletRequest){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")publicStringgetNameByParam(@RequestParamString userName);

Post请求传递请求头

@PostMapping("/body")publicStringgetNameByBody(@RequestBodyString userName);

路径参数

@GetMapping("/timeout/{millis}")publicStringtimeout(@PathVariablelong millis);

文件上传

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

多文件上传

@PostMapping(value="/files",consumes=MediaType.MULTIPART_FORM_DATA_VALUE)publicIterable<String>files(@RequestPart("file2")Collection<MultipartFile>  file);
  • 作者:爱码猿
  • 原文链接:https://blog.csdn.net/dndndnnffj/article/details/121453687
    更新时间:2022年12月2日08:59:12 ,共 6830 字。