基础操作
pom依赖
OpenFeign
是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置application.yml
#====《跨服务HTTP接口请求工具》====
feign:
client:
config:
#可指定需要配置的:服务名称
# manage-client:
#或 默认配置:全局
default:
#日志打印级别
loggerLevel: basic
#跨服务接口请求超时
readTimeout: 5000
#跨服务请求连接超时
connectTimeout: 5000
服务启动类
启动类加上注解:@EnableDiscoveryClient
文章来源:https://www.toymoban.com/news/detail-431152.html
@SpringBootApplication
@EnableDiscoveryClient
public class OpenFeignServer {
public static void main(String[] args) {
SpringApplication.run(OpenFeignServer.class, args);
}
}
基础跨服务调用
/**
* @Author Owen
* @Date 2020/8/18
* @Description Admin后台管理服务
*/
@FeignClient("serverName")
public interface AdminServiceClient {
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.GET, produces = {"application/json"}, consumes = {"application/glue+json"})
<T> T doGet(@RequestParam("params") String params);
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.PUT, produces = {"application/json"}, consumes = {"application/communication+json"})
<T> T doPut(@RequestBody Object params);
@RequestMapping(value = "/XXX/XXXX/XXXX", method = RequestMethod.POST, produces = {"application/json"}, consumes = {"application/communication+json"})
<T> T doPost(@RequestBody Object params);
}
动态IP+URL请求 + 动态编码器\解码器
自定义跨服务请求,Encoder编译器
import com.details.utils.ConvertUtils;
import com.details.utils.JsonUtils;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.RequestTemplate;
import feign.Util;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
/**
* @author Owen
* @date 2022/10/22 21:10
* @Description:自定义Feign跨服务请求,编译器
*/
@Slf4j
public class FeignEncoder implements Encoder {
ObjectMapper mapper = new ObjectMapper();
@SneakyThrows
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
log.info("Feign requset encode details: {}", object);
try {
//获取请求头详情
Map<String, Collection<String>> headers = template.headers();
//查看请求方式
Collection<String> contentType = headers.get("Content-Type");
//Json请求方式
if (CollectionUtils.isNotEmpty(contentType) && contentType.contains("application/json") && !(object instanceof String)) {
template.body(JsonUtils.object2Json(object));
}
//字符串
else if (object instanceof String) {
template.body(object.toString());
} else {
JavaType javaType = this.mapper.getTypeFactory().constructType(bodyType);
template.body(ConvertUtils.writeAsBytes(javaType, object), Util.UTF_8);
}
} catch (Exception e) {
throw new EncodeException(String.format("%s is not a type supported by this encoder.", object.getClass()));
}
}
}
自定义跨服务响应,Decoder 解码器
import feign.Response;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Type;
/**
* @author Owen
* @date 2022/10/22 21:10
* @Description:自定义Feign跨服务响应,解码器
*/
@Slf4j
public class FeignDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) {
log.info("URL:[{}] response result: {}", response.request().url(), response);
return response.body();
}
}
方式1:FeignFactory.class
动态URL文章来源地址https://www.toymoban.com/news/detail-431152.html
import feign.*;
import java.net.URI;
/**
* @Author: Owen
* @Date: 2022/10/22
* @Description:Feign公共接口(自定义请求API,内部请求)
*/
public interface FeignFactory {
/**
* @param host 接口主机地址,如:http://localhost:8080,该参数是实现动态URL的关键
* @param path 接口路径,如:/test/hello
* @param body 请求消息体对象
* @Author: Owen
* @Date: 2022/10/22
* @Description:通用POST请求,请求消息体格式为JSON
*/
@RequestLine("POST {path}")
@Headers({"Content-Type: application/json", "Accept: application/json"})
<T> T doPost(URI host,@Param("path") String path, Object body);
/**
* @param host 接口主机地址
* @param path 接口路径,如:/test/hello
* @Author: Owen
* @Date: 2022/10/22
* @Description:通用Get请求
*/
@RequestLine("POST {path}")
<T> T doGet(URI host, @Param("path") String path);
}
工具类: FeignUtils.class
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.details.nacos.NacosFactory;
import com.details.utils.CacheUtils;
import com.details.utils.ExceptionUtils;
import com.details.utils.IocUtils;
import com.details.utils.TcpIpUtils;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import lombok.extern.slf4j.Slf4j;
import java.net.URI;
import java.util.*;
/**
* @author: Owen
* @date: 2021/3/24
* @description:跨服务API请求工具 集成Spring openfeign各个功能
* 动态设置 编译器 解码器 熔断器
* 跨服务器 动态API请求 自定义构建 IP(单机\集群)+服务名
*/
@Slf4j
public class FeignUtils {
private static Feign.Builder feignClient = null;
/**
* @param ip 对应服务器公网IP
* @param path API接口地址
* @Author: Owen
* @Date: 2022/10/22
* @Description:通用Get请求
*/
public static <T> T doGet(String ip, String path) {
T result = null;
ExceptionUtils.isBlank(ip, "Params :[ip] is null !");
ExceptionUtils.isBlank(ip, "Params :[path] is null !");
ExceptionUtils.isTrue(!ip.contains(":"), "Ip port not null!");
ExceptionUtils.isTrue(!ip.contains("http://"), "Ip formal error, lack \"http://\"");
try {
//构建Feign基础实例
Feign.Builder client = feigenClient();
ExceptionUtils.isNull(client, "Feign client is null !");
//自定义配置
client.encoder(new FeignEncoder()); //API请求 编译器
client.decoder(new FeignDecoder()); //API响应 解码器
client.logger(new Slf4jLogger()); //日志
client.logLevel(Logger.Level.FULL); //日志级别
//构建工厂
//注意:这里的url参数不能为空字符串,但是可以设置为任意字符串值,在这里设置为“EMPTY”
FeignFactory factory = client.target(FeignFactory.class, "EMPTY");
//跨服务请求
result = factory.doGet(URI.create(ip), path);
} catch (Exception e) {
log.error("HTTP get requset faild: {}", e.getMessage());
}
return result;
}
/**
* @param ip 对应服务器公网IP
* @param path API接口地址
* @param body Json数据体
* @Author: Owen
* @Date: 2022/10/22
* @Description:跨服务POST请求接口,类型:application/json
*/
public static <T> T doPost(String ip, String path, Object body) {
T result = null;
ExceptionUtils.isBlank(ip, "Params :[ip] is null !");
ExceptionUtils.isBlank(ip, "Params :[path] is null !");
ExceptionUtils.isNull(body, "Params :[body] is null !");
ExceptionUtils.isTrue(!ip.contains(":"), "ip port not null!");
ExceptionUtils.isTrue(!ip.contains("http://"), "Ip formal error, lack \"http://\"");
try {
//构建Feign基础实例
Feign.Builder client = feigenClient();
ExceptionUtils.isNull(client, "Feign client is null !");
//自定义配置
client.encoder(new FeignEncoder()); //API请求 编译器
client.decoder(new FeignDecoder()); //API响应 解码器
client.logger(new Slf4jLogger()); //日志
client.logLevel(Logger.Level.FULL); //日志级别
FeignFactory factory = client.target(FeignFactory.class, ip);
//跨服务请求
result = factory.doPost(URI.create(ip), path, body);
} catch (Exception e) {
log.error("HTTP post requset faild: {}", e.getMessage());
}
return result;
}
/**
* @author: Owen
* @date: 2020/12/4
* @description:获取Feign实例(单例模式)
*/
private static Feign.Builder feigenClient() {
try {
//feign客户端(http跨服务请求 单例模式)
if (Objects.isNull(feigenClient)) {//第一次判空
//保证线程安全
synchronized (Feign.Builder.class) {
//第二次判空,保证单例对象的唯一性,防止第一次有多个线程进入第一个if判断
if (Objects.isNull(feigenClient)) {
try {
feigenClient = Feign.builder();
} catch (Exception e) {
log.error("Feigen client initialize fail: " +e.getMessage());
}
}
}
}
} catch (Exception e) {
log.error("Feigen client get faild: {}", e.getMessage());
}
return feigenClient;
}
}
方式2:FeignApiFactory.class
import feign.*;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.net.URI;
/**
* @Author: Owen
* @Date: 2022/10/22
* @Description:Feign公共接口(走网关转发)
*/
@FeignClient(value = "server-gateway", url = "EMPTY", configuration = FeignApiFactory.CallbackConfiguration.class)
public interface FeignApiFactory {
/**
* @param host 接口主机地址,如:http://localhost:8080
* @param path 接口路径,如:/test/hello
* @param body 请求消息体对象
* @Author: Owen
* @Date: 2022/10/22
* @Description: 统一回调接口方法,请求消息体格式为JSON,响应消息体格式也为JSON
*/
@RequestMapping(value = "{path}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
<T> T doPost(URI host, @PathVariable("path") String path, @RequestBody Object body);
/*
==========《Deme》==========:
String uri = "http://localhost:8080";
Map<String, Object> queryMap = new HashMap<>(0);
queryMap.put("k","v");
Map<String,Object> body = new hashMap<String,Object>();
body.put("params1","value");
Object result = this.callbackAPI.callback(URI.create(uri), "/test/apiTest", queryMap, body);
*/
//自定义回调接口配置
@Component
class CallbackConfiguration {
@Bean
public Encoder feignEncoder() {
return new FeignEncoder();
}
@Bean
public Decoder feignDecoder() {
return new FeignDecoder();
}
@Bean
public Retryer feignRetryer() {
return new Retryer.Default();
}
@Bean
public Logger feignLogger() {
return new Slf4jLogger();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
}
到了这里,关于SpringBoot项目整合OpenFeign、实现动态IP+URL请求、自定义(编码器\解码器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!