问题:Spring Cloud Gateway自带的断言(Predicate)不满足业务怎么办?可以自定义断言!
先看Spring Cloud Gateway是如何实现断言的
Gateway中断言的整体架构如下:
public abstract class AbstractRoutePredicateFactory<C> extends AbstractConfigurable<C>
implements RoutePredicateFactory<C> {
public AbstractRoutePredicateFactory(Class<C> configClass) {
super(configClass);
}
}
可以看到Gateway的断言都是继承了AbstractRoutePredicateFactory
抽象类。
自定义路由断言规则的步骤如下:
- 新建类名
CustomRoutePredicateFactory
(类名需要以以RoutePredicateFactory结尾),并继承AbstractRoutePredicateFactory
抽象类。 - 重写apply()方法
- 新建apply()方法所需的静态内部类
CustomRoutePredicateFactory.Config
,这个Config就是我们的断言规则 - 空参构造方法,内部调用super()方法
- 在Config类中配置自定义参数
- apply()中编写自定义的逻辑
import jakarta.validation.constraints.NotNull;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.web.server.ServerWebExchange;
import java.util.function.Predicate;
/**
* 自定义路由断言工厂,指定的用户类型才能访问
*
* @author gengduc@qq.com
* @since 2024-03-08
*/
@Component
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
public CustomRoutePredicateFactory() {
super(CustomRoutePredicateFactory.Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(CustomRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
// 这里可以编写自定义的逻辑
// 获取请求中的信息,判断是否符合条件
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
if (userType == null) {
return false;
}
// 判断用户类型是否符合
return userType.equalsIgnoreCase(config.getUserType());
}
};
}
public static class Config {
// 这里可以配置一些参数
@NotNull
private String userType;
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
}
}
这个时候已经可以使用我们自定义的断言了。
http://localhost:9527/order/gateway/get/1?userType=admin
在yml文件中配置:
spring:
cloud:
gateway:
routes:
- id: custom_route
uri: https://example.org
predicates:
- name: Custom
args:
userType: admin # 当用户类型是admin的时候进行路由转发
可以看到我们使用的配置方式是完全展开的参数配置方式(Fully Expanded Arguments),这个时候还是不支持快捷配置的。
为了让自定义的断言支持快捷配置(Shortcut Configuration),还需要实现shortcutFieldOrder()
方法。
完整的代码如下:
import jakarta.validation.constraints.NotNull;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.web.server.ServerWebExchange;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
/**
* 自定义路由断言工厂,指定的用户类型才能访问
*
* @author gengduc@qq.com
* @since 2024-03-08
*/
@Component
public class CustomRoutePredicateFactory extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
public CustomRoutePredicateFactory() {
super(CustomRoutePredicateFactory.Config.class);
}
// 快捷配置支持
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("userType");
}
@Override
public Predicate<ServerWebExchange> apply(CustomRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
// 这里可以编写自定义的逻辑
// 获取请求中的信息,判断是否符合条件
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
if (userType == null) {
return false;
}
// 判断用户类型是否符合
return userType.equalsIgnoreCase(config.getUserType());
}
};
}
public static class Config {
// 这里可以配置一些参数
@NotNull
private String userType;
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
}
}