官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

注册中心使用的Eureka

1.创建模块

1.1创建模块cloud-gateway-gateway9527

1.2pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion> <artifactId>cloud-gateway-gateway9527</artifactId> <dependencies> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency> <dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> </dependencies> </project>

1.3yml文件

server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get1/** #断言,路径相匹配的进行路由 eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

关于gateway的route的配置说明

  id:路由的id,随便取,不要重复

  uri:实际的服务提供者的地址,也就是需要路由过去的地址

  predicates:断言,访问9527时,判断路径是否符合断言的规则。是,则进行路由。如:访问http://localhost:9527/payment/get/1。符合断言的匹配规则,此时进行路由,路由到http://localhost:8001/payment/get/1

1.4主启动类

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class,args);
}
}

1.5测试

  访问http://localhost:9527/payment/get/1

 

2.使用编码来配置gateway路由断言

这是上面在yml文件进行配置

 cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由

也可以不这样配置,采用编码的方式来配置

package com.atguigu.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* @Classname GateWayConfig
* @Description TODO
* @Date 2021/5/14 0014 下午 2:39
* @Created by jcc
*/ @Configuration
public class GateWayConfig { /*
这里的配置相当于yml里面的配置
gateway:
routes:
- id: path_rote_atguigu  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://news.baidu.com #匹配后提供服务的路由地址---这里访问的是百度的新闻网站-用外网做下测试
predicates:
- Path=/guonei #断言,路径相匹配的进行路由*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com")).build();
return routes.build();
} //再配置一个
@Bean
public RouteLocator customRouteLocator2(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_rote_atguigu", r -> r.path("/guoji").uri("http://news.baidu.com")).build();
return routes.build();
} }

  两种配置方式都可以。

3.配置动态路由

  上面配置路由,服务路径都是写的http://localhost:8001。如果这个服务是集群呢,难道去配置集群中的每一个服务吗?

   可以这样子来配置

   加入cloud: gateway: discovery: locator: enabled: true

   修改uri属性: uri: lb://cloud-payment-hystrix-service #服务在注册中心的名称。使用服务名称来代替地址

server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment_routh  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #服务在注册中心的名称
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由 - id: payment_routh2  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #服务在注册中心的名称
predicates:
- Path=/payment/get1/** #断言,路径相匹配的进行路由 eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

4.断言

4.1断言工厂

  官方提供了11种

  

4.1.1The After Route Predicate Factory

 - After=2017-01-20T17:42:47.789-07:00[America/Denver] 表示在某个时间之后开始生效(这里是美国时间,可有使用国内时间) 

spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]

4.1.2The Before Route Predicate Factory

- Before=2017-01-20T17:42:47.789-07:00[America/Denver]  表示在某个时间之前有效
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

4.1.3 The Between Route Predicate Factory

 - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] 在这段时间内有效
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

4.1.4 The Cookie Route Predicate Factory

 - Cookie=chocolate, ch.p   必须携带cookie,名称为chocolate,值和正则表达式ch.p匹配
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p

4.1.5 The Header Route Predicate Factory

- Header=X-Request-Id, \d+  请求具有名为X-Request-Id,其值与\d+正则表达式匹配的标头
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+

 4.1.6The Host Route Predicate Factory

 - Host=**.somehost.org,**.anotherhost.org    请求的Host标头值为www.somehost.orgbeta.somehost.org或,则此路由匹配www.anotherhost.org
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org

4.1.7 The Method Route Predicate Factory

- Method=GET,POST  请求方式为GET 或者 POST
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST

4.1.8The Path Route Predicate Factory

- Path=/red/{segment},/blue/{segment}  路径匹配
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}

4.1.9 The Query Route Predicate Factory

- Query=green  请求包含green查询参数
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green

4.1.10The RemoteAddr Route Predicate Factory

 - RemoteAddr=192.168.1.1/24   请求方的ip匹配  192.168.1.1  到 192.168.1.24
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24

4.1.11The Weight Route Predicate Factory

- Weight=group1, 2   将大约80%的流量转发到weighthigh.org,将大约20%的流量转发weightlow.org。相当于负载均衡的配置

spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2

4.2组合配置

 - Path=/payment/get/**   #断言,路径相匹配的进行路由
- AFTER=2022-01-20T17:42:47.485-08:00[Asia/Shanghai] #断言 时间在2022-01-20 17:42:47 后生效
在在2022-01-20 17:42:47之后,路径匹配符合 /payment/get/**的请求断言判定成功
      routes:
- id: payment_routh  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- AFTER=2017-01-20T17:42:47.485-08:00[Asia/Shanghai]

5. Filter(转https://blog.csdn.net/forezp/article/details/85057268)

5.1filter基本

当我们有很多个服务时,比如下图中的user-service、goods-service、sales-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事情,比如鉴权、限流、日志输出等。


对于这样重复的工作,有没有办法做的更好,答案是肯定的。在微服务的上一层加一个全局的权限控制、限流、日志输出的Api Gatewat服务,然后再将请求转发到具体的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外接的请求访问系统,必须先通过网关层。


5.2生命周期
Spring Cloud Gateway同zuul类似,有“pre”(请求前)和“post”(请求后)两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,比如上图中的user-service,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端

与zuul不同的是,filter除了分为“pre”和“post”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。现在从作用范围划分的维度来讲解这两种filter

5.3Gateway Filter

  https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

5.3.1介绍

  过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud Gateway包含许多内置的GatewayFilter工厂。
  GatewayFilter工厂是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。在配置文件中配置的GatewayFilter Factory最终都会相应的过滤器工厂类处理。
Spring Cloud Gateway 内置的过滤器工厂一览表如下

  现在挑几个常见的过滤器工厂来讲解,每一个过滤器工厂在官方文档都给出了详细的使用案例,如果不清楚的还可以在org.springframework.cloud.gateway.filter.factory看每一个过滤器工厂的源码。

5.3.2截个filter介绍

  1)AddRequestHeader GatewayFilter Factory
  创建工程,gateway依赖如下:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

在工程的配置文件中,加入以下的配置

filters:
- AddRequestHeader=X-Request-red, blue

完整配置

server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment_routh  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
filters:
- AddRequestHeader=X-Request-red, blue - id: payment_routh2  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get1/** #断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
filters:
- AddRequestHeader=X-Request-red, blue eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

  配置了一个filter为AddRequestHeaderGatewayFilterFactory(约定写成AddRequestHeader),AddRequestHeader过滤器工厂会在请求头加上一对请求头,名称为X-Request-Foo,值为Bar。为了验证AddRequestHeaderGatewayFilterFactory是怎么样工作的,查看它的源码,AddRequestHeaderGatewayFilterFactory的源码如下:

public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), config.getValue())
.build(); return chain.filter(exchange.mutate().request(request).build());
};
} }

由上面的代码可知,根据旧的ServerHttpRequest创建新的 ServerHttpRequest ,在新的ServerHttpRequest加了一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤

  测试访问

   在服务提供方代码修改

@GetMapping(value = "/payment/get1/{id}")
public String create(@PathVariable("id") Long id,HttpServletRequest request){
String header = request.getHeader("X-Request-red");
System.out.println(header);
return paymentService.paymentInfo_OK(id);
}

  访问

  

  服务提供方控制台打印blue,说明请求头中X-Request-red:blue成功添加

跟AddRequestHeader过滤器工厂类似的还有AddResponseHeader过滤器工厂,在此就不再重复

 2)RewritePath GatewayFilter Factory

  在Nginx服务启中有一个非常强大的功能就是重写路径,Spring Cloud Gateway默认也提供了这样的功能,这个功能是Zuul没有的。在配置文件中加上以下的配置

spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://blog.csdn.net
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}

  上面的配置中,所有的/foo/**开始的路径都会命中配置的router,并执行过滤器的逻辑,在本案例中配置了RewritePath过滤器工厂,此工厂将/foo/(?.*)重写为{segment},然后转发到https://blog.csdn.net。比如在网页上请求localhost:8081/foo/forezp,此时会将请求转发到https://blog.csdn.net/forezp的页面,比如在网页上请求localhost:8081/foo/forezp/1,页面显示404,就是因为不存在https://blog.csdn.net/forezp/1这个页面

5.4自定义GatewayFilter过滤器

  https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#global-filters 

   Spring Cloud Gateway内置了多种强大的过滤器工厂,能够满足很多场景的需求,那么能不能自定义自己的过滤器呢,当然是可以的。

 1)在spring Cloud Gateway中,过滤器需要实现GatewayFilter和Ordered2个接口。写一个RequestTimeGatewayFilter ,代码如下

package com.atguigu.springcloud.filter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; /**
* @Classname RequestTimeFilter
* @Description TODO
* @Date 2021/5/17 0017 下午 2:28
* @Created by jcc
*/
@Component
public class RequestTimeGatewayFilter implements GatewayFilter, Ordered { private static final Log log = LogFactory.getLog(GatewayFilter.class);
private static final String REQUEST_TIME_BEGIN = "requestTimeBegin"; @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
if (startTime != null) {
log.info("myfilter: " + exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
})
); } @Override
public int getOrder() {
return 0;
}
}

在上面的代码中,Ordered中的int getOrder()方法是来给过滤器设定优先级别的,值越大则优先级越低。还有有一个filterI(exchange,chain)方法,在该方法中,先记录了请求的开始时间,并保存在ServerWebExchange中,此处是一个“pre”类型的过滤器,然后再chain.filter的内部类中的run()方法中相当于"post"过滤器,在此处打印了请求所消耗的时间。

  2)把这个过滤器加入到过滤工厂,并且添加到Spring容器中

package com.atguigu.springcloud.config;

import com.atguigu.springcloud.filter.RequestTimeGatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component; /**
* @Classname FilterConfig
* @Description TODO
* @Date 2021/5/17 0017 下午 2:29
* @Created by jcc
*/
@Component
public class RequestTimeGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> { @Override
public GatewayFilter apply(Object config)
{
return new RequestTimeGatewayFilter();
} }

查看GatewayFilterFactory的源码,可以发现GatewayFilterfactory的层级如下:

过滤器工厂的顶级接口是GatewayFilterFactory,有2个两个较接近具体实现的抽象类,分别为AbstractGatewayFilterFactory和AbstractNameValueGatewayFilterFactory,这2个类前者接收一个参数,比如它的实现类RedirectToGatewayFilterFactory;后者接收2个参数,比如它的实现类AddRequestHeaderGatewayFilterFactory类。现在需要将请求的日志打印出来,需要使用一个参数,这时可以参照RedirectToGatewayFilterFactory的写法

  3)yml中配置

 filters:- RequestTime

   完整配置

server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment_routh  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
filters:
- AddRequestHeader=X-Request-red, blue
- RequestTime - id: payment_routh2  #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-hystrix-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get1/** #断言,路径相匹配的进行路由
- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
filters:
- AddRequestHeader=X-Request-red, blue
- RequestTime eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

测试 :

控制台打印:

5.5 global filter

 Spring Cloud Gateway根据作用范围划分为GatewayFilter和GlobalFilter,二者区别如下:

    GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

    GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。

Spring Cloud Gateway框架内置的GlobalFilter如下:

上图中每一个GlobalFilter都作用在每一个router上,能够满足大多数的需求。但是如果遇到业务上的定制,可能需要编写满足自己需求的GlobalFilter。

5.6自定义GlobalFilter

在下面的案例中将讲述如何编写自己GlobalFilter,该GlobalFilter会校验请求中是否包含了请求参数“token”,如何不包含请求参数“token”则不转发路由,否则执行正常的逻辑。代码如下:

public class TokenFilter implements GlobalFilter, Ordered {

    Logger logger=LoggerFactory.getLogger( TokenFilter.class );
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (token == null || token.isEmpty()) {
logger.info( "token is empty..." );
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
} @Override
public int getOrder() {
return -100;
}
}

注入spring

@Configuration
public class FilterConfig { @Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
}

 测试访问

  

  由于没有带token,被拦截了,控制台打印

  

  

  

  

最新文章

  1. 虚拟机linux上网问题
  2. 关于sort排序
  3. D3.js 力导向图
  4. Xcode 报错信息
  5. VS类自定义版权注释
  6. s​e​t​ ​x​a​c​t​_​a​b​o​r​t ​用​法
  7. logstash 判断接口响应时间发送zabbix告警
  8. euctb
  9. asp.net用Zxing库实现条形码输出
  10. zabbix 布署实践【4 服务器自动探索发现,并且自动关联模版】
  11. js原生设计模式——10适配器模式之参数适配器
  12. cocos2dx截整屏、截部分屏
  13. [搬运] 将 Visual Studio 的代码片段导出到 VS Code
  14. [工具开发] 分享两个基于Heapster 和 Influxdb 的 Grafana 监控仪表盘模板
  15. 【转】反编译D-Link路由器固件程序并发现后门
  16. HTML5与CSS3权威指南笔记案例1
  17. React native 之设置IOS的图标,名称和启动图(下篇文章会讲到RN的android的相关设置)
  18. C# 生成指定N位随机码
  19. AOP 貌似是拦截器 对方法进行拦截
  20. $.meta ? $.extend({}, opts, $this.data()) : opts 是什么

热门文章

  1. 高精度加法(Java)
  2. 2022春每日一题:Day 30
  3. ftp多用户多目录配置
  4. 数据结构篇——KMP算法
  5. ARMv8之memory model和Observability(四)
  6. vscode配置remote ssh
  7. 关于Wegame页面空白的问题解决
  8. 【每日一题】【优先队列、迭代器、lambda表达式】2022年1月15日-NC119 最小的K个数
  9. Win10系统安装U盘,安装纯净版Win10的通用教程
  10. SQLMap入门——获取当前网站数据库的名称