com.ruoyi.gateway
今天简单看看若依的gateway的配置模块干了啥
最近面试很多外包公司,都对低代码平台有点要求,这些代码虽说用起来不费劲,但是其中还是有很多细节能让我学习学习的。(微服务版,上次搞jeecgboot的笔试题差点把我人带走了)
简单的看一眼,总共分为4个文件夹和1个启动类。
0. pom文件
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.4</version>
</parent>
dependencies
spring-cloud-starter-gateway
spring-cloud-starter-alibaba-nacos-discovery
spring-cloud-starter-alibaba-nacos-config
spring-cloud-starter-alibaba-sentinel
spring-cloud-alibaba-sentinel-gateway
sentinel-datasource-nacos
spring-boot-starter-actuator
spring-cloud-loadbalancer
kaptcha
ruoyi-common-redis
springdoc-openapi-webflux-ui
1. 先看一眼启动类
emm,没什么特别就加了一个注解,用来剔除数据库的自动配置的。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
2. 从头开始看,第一个是config
- config
- properties(首先也是一个目录,里面写了一些属性)
- CaptchaConfig:验证码的配置
- GatewayConfig:网关限流配置
- KaptchaTextCreator:验证码文本生成器(这里是no usages的)
- RouterFunctionConfiguration:路由配置
- SpringDocConfig:文档的配置类
CaptchaConfig
这里用的是google的kaptcha的包,里面注册了两个bean,一个是default的验证码bean,一个是数字的bean。
GatewayConfig:这里主要是注册了一个自定义的限流处理
@Configuration
public class GatewayConfig{
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
// 这里的SentinelFallbackHandler自定义的限流处理,跳转过去看看
public SentinelFallbackHandler sentinelGatewayExceptionHandler(){
return new SentinelFallbackHandler();
}
}
// 自定义限流异常处理
public class SentinelFallbackHandler implements WebExceptionHandler{
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange){
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex){
if (exchange.getResponse().isCommitted()){
return Mono.error(ex);
}
if (!BlockException.isBlockException(ex)){
return Mono.error(ex);
}
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable){
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
}
}
好像没啥特别,就是封装了一些自定义的返回,ServletUtils.webFluxResponseWriter这里也是一个返回的封装。
@Order(Ordered.HIGHEST_PRECEDENCE)
@Order用于指定Bean的加载顺序,注解的参数越小优先级越高,越会被优先加载。
public interface Ordered {
int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;
int LOWEST_PRECEDENCE = Integer.MAX_VALUE;
int getOrder();
}
KaptchaTextCreator 这个就不展开研究了,给我的话可能梭哈cv一下就完事了。
RouterFunctionConfiguration
这个配置类里面注入了handler的ValidateCodeService,这个类主要是用于获取验证码的
@Autowired
private ValidateCodeHandler validateCodeHandler;
@Bean
public RouterFunction routerFunction() {
// 当接收到 /get的请求以及 ediaType.TEXT_PLAIN的时候就跑到handler里面去,也就是注入的获取验证码的handler
return RouterFunctions.route(
RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
validateCodeHandler);
}
// handler里面调用创建验证码的方法
@Component
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> {
@Autowired
private ValidateCodeService validateCodeService;
@Override
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
AjaxResult ajax;
try {
ajax = validateCodeService.createCaptcha();
} catch (CaptchaException | IOException e) {
return Mono.error(e);
}
return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
}
}
也是注册了一个bean,返回了.route
这个方法,也跳转进去看看干嘛的。
/**
* Route to the given handler function if the given request predicate applies.
* <p>For instance, the following example routes GET requests for "/user" to the
* {@code listUsers} method in {@code userController}:
* <pre class="code">
* RouterFunction<ServerResponse> route =
* RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers);
* </pre>
* @param predicate the predicate to test
* @param handlerFunction the handler function to route to if the predicate applies
* @param <T> the type of response returned by the handler function
* @return a router function that routes to {@code handlerFunction} if
* {@code predicate} evaluates to {@code true}
* @see RequestPredicates
*/
public static <T extends ServerResponse> RouterFunction<T> route(
RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
// 这里就类似对断言进行了配置
return new DefaultRouterFunction<>(predicate, handlerFunction);
}
SpringDocConfig
这里做的是swagger的配置,多看了一眼这个订阅类型方法,好像是返回一些nacos的东西的,具体还得研究一下。
@Override
public Class<? extends Event> subscribeType() {
return InstancesChangeEvent.class;
}
3. filter
AuthFilter:网关鉴权
// 实现两个类
public class AuthFilter implements GlobalFilter, Ordered
嗯?这个实现Ordered的类居然还能这样用,属实是我太菜了,这样就又能自己定义优先级了
@Override
public int getOrder() {
return -200;
}
其余的就是一些基本的鉴权验证了,判断令牌的状态等等等等
BlackListUrlFilter:黑名单过滤器
extends AbstractGatewayFilterFactory<>,网关的filter factory。
重写了GatewayFilterFactory里面的apply,然后判断是否为黑名单然后返回一个封装好的数据。(一个类套一个好家伙,倒也不复杂,果然写得好看的代码就是绕)
CacheRequestFilter:获取body的请求数据
这个又是个什么玩意?解决流不能重复读取的问题?也跟黑名单过滤器一样继承了相同的一个东西,然后在泛型里自己定义一个内部类来搞。
ValidateCodeFilter:验证码过滤器
跟上面也是同样的,what?AbstractGatewayFilterFactory这个东西有点牛的。
XssFilter:跨站脚本过滤器
implements GlobalFilter, Ordered
同样是实现了ordered,并且这次也实现了GlobalFilter这个东西,重写filter方法,主要是用来过滤请求的。这些类可以拿过来就用了。
4. handler
这里面的类都会在上面的类中被调用而抽出来放的。
- 网关统一处理的异常
- 自定义限流异常处理
- 验证码的获取(这个在service中也抽出来了)
差不多就这样,得看看这个AbstractGatewayFilterFactory<>是个什么来头
看这个类的写法,跟若以这里抽出来的写的确实是类似的,但是apply方法不是放在这里的,还在上一级的GatewayFilterFactory中,确实里面都会搭配上一个内部类来使用。
这里就是上一级的GatewayFilterFactory
原来每一次都需要定义一个内部类是因为这里是一个class,所以为了方便直接就丢里面。
#学习完毕,done