SpringCloud(六)Gateway 路由网关_spring.cloud.gateway.httpclient.-程序员宅基地

技术标签: Gateway  SpringCloud  Spring Cloud 学习  


一、Gateway是什么?

GateWay 是 Spring 生态系统之上构建的API网关服务, 基于 Spring5,SpringBoot 2 和Project Reactor 等技术。

Gateway 旨在提供一种简单而有效的方式来对 API 进行路由, 以及提供一些强大的过滤功能, 例如 熔断, 限流, 重试等。

SpringCloud Gateway 是SpringCloud 的一个全新项目,基于Spring 5 和 Spring Boot 2.0 Project Reactor 等技术开发的网关, 他是为了微服务提供一种简单有效的API路由管理方式

SpriingCloud Gateway 作为 Spring Cloud 生态系统中的网关, 目标是替代 Zuul,在Spring Cloud 2.0以上版本, 没有新版本的 Zuul2.0 以上最新版本的进行集成,仍然还是使用Zuul 1.x 非Reactor 模式的老版本, 而为了提升网关的性能, Spring Cloud Gateway 是基于 WebFlux 框架实现的, 而WebFlux 框架底层则使用了高性能的Reactor 模式通信的框架 Netty

SpringCloud Gateway 的目标是提供统一的路由方式且基于 Filter 链的方式提供了网关的基本功能, 例如: 安全, 监控、 限流,

1.1、网关位置

在这里插入图片描述

1.2 Gateway特性

  • 基于异步非阻塞模型
  • 基于Spring 5, Project Reactor 和 SpringBoot 2.0
  • 动态路由,能够匹配任何请求属性
  • 可以对路由指定 Predicate(断言) 和 Filter (过滤器)
  • 集成Hystrix 的断路器功能
  • 集成 Spring Cloud 的服务发现功能
  • 易于编写的 Predicate 和 Filter
  • 请求限流功能
  • 支持路径重写

传统的Web 框架,比如说 struts2, SpringMVC 等都是基于 Servlet API和servlet 容器基础之上,但是,在Servlet 3.1 之后有了异步非阻塞的支持,而WebFlux 是一个典型的非阻塞异步的框架,他的核心是基于 Reactor 的相关API实现的,相对于传统的 web 框架来说, 他可以在Netty, Undertow 及 支持Servlet 3.1 的容器上, 非阻塞式 + 函数式编程

Spring WebFlux 是 Spring 5.0 引入的新的响应式框架,区别于SpringMVC, 他不需要依赖 Servlet API, 他是完全异步非阻塞的。 并且基于 Reactor来实现响应式规范。

  • Route(路由): 路由是构建网关的基本模块, 他由ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由
  • Predicate(断言):参考java8 中的 java.util.function.Predicate 开发人员可以匹配http请求中的所有内容,比如请求头或者请求参数, 如果请求参数与断言相匹配则进行路由。
  • Filter(过滤):指的是Spring框架中Gateway Filter 的实例, 使用过滤器,可以在请求路由前或者之后进行修改。
    在这里插入图片描述
    web,请求,通过一些匹配条件(断言),定位到真正的服务节点,并且在这个转发过程的前后进行一些精细化控制, Predicate 就是我们的匹配条件而Filter,就可以理解为一个无所不能的拦截器,有了这两个元素,再加上目标的URI, 就可以实现一个具体的路由了

官方示意图
在这里插入图片描述
客户端向Gateway 发出请求, 然后在Gateway Handler Mapping 中找到请求相匹配的路由, 将其发送到Gateway Web Handler
Handler 在通过制定的过滤器链来讲请求发送到我们实际的服务执行业务逻辑,然后返回,过滤器链之间用虚线分开是因为过滤器可能会在发送代理之前 (“pre”) 或之后 (“post”)

二、使用步骤

1.1 创建项目工程模块 sgg-gateway-api9527

引入依赖

  <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.fllday</groupId>
            <artifactId>sgg-api-common</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

1.2 配置 yml 文件

server:
  port: 9527
spring:
  application:
    name: cloud-gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启动态路由
      routes:
        - id: payment-service # 路由唯一id
          uri: lb://SGG-PAYMENT-SERVICE # lb 代表 负载均衡loadBalances , 后面跟着的是微服务名称 在 eureka 中注册的名字
          predicates: # 断言
            - Path=/** # 判断是否匹配
eureka:
  instance:
    hostname: cloud-gateway-service
    instance-id: cloud-gateway-service-${
    server.port}
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka

1.3 配置启动类

@SpringBootApplication
@EnableEurekaClient
public class Gateway9527App {
    
    public static void main(String[] args) {
    
        SpringApplication.run(Gateway9527App.class, args);
    }
}

顺序启动 7001, 7002,8001, 8002, 9527 。

通过我们的网关访问我们的payment 提供的接口
http://localhost:9527/SGG-PAYMENT-SERVICE/payment/111SGG-PAYMENT-SERVICE 就是我们配置的 lb 负载均衡 的服务名 后面就匹配我们的 -Path 断言
在这里插入图片描述
可以看到我们通过网关访问, 网关顺利转发到真正的服务接口上。 同时还具有负载均衡的效果。
在这里插入图片描述

1.4 Gateway 默认提供的断言

在这里插入图片描述
都可以试试。
有兴趣的可以自己尝试一下。 官网介绍

1.5 如何自定义断言工厂

我们可以看一下其他的断言类。发现都是继承自 AbstractRoutePredicateFactory 我们也来尝试自己定义一个 断言工厂
注意项:

  • 自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑和shortcutFieldOrder方法。
  • 在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。
  • 命名需要以 RoutePredicateFactory 结尾,比如 CheckAuthRoutePredicateFactory,那么在使用的时候 CheckAuth 就是这个路由断言工厂的名称。代码如下所示。

创建 PortPredicateFactory.java

@Component
@Slf4j
public class PortPredicateFactory extends AbstractRoutePredicateFactory<PortPredicateFactory.Config> {
    
     public PortRoutePredicateFactory() {
    
        super(Config.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
    
        return serverWebExchange -> {
    
         	ServerHttpRequest request = exchange.getRequest();
            ApplicationContext applicationContext = exchange.getApplicationContext();
            if (config.getPort().equals(new Integer("8001"))) {
    
                return true;
            }
            return false;
        };
    }
    @Data
    public class Config {
    
        private Integer port;
    }
}

上面的意思就是如果 端口号为 8001 就可以执行, 不等于 8001 就不执行。 可以看到 通过 exchange 参数我们可以获取到很多东西。 这个时候就可以通过这些东西做很多事情。 具体的我就不演示了。 现在配置yml 文件试试吧。
修改 yml 文件

routes:
  - id: payment-service
    uri: lb://SGG-PAYMENT-SERVICE
    predicates:
      - Path=/**
      - Port=8001

重启服务访问 接口。
在这里插入图片描述
使用 8001 的时候,访问没有问题。 我们修改配置类将 -Port=8002 试试

1.6 Route Filter

一下都是转自 芋道源码
Gateway 内置了许多种 Route Filter 实现。 对请求进行拦截 实现自定义的功能, 比如说,限流。熔断等功能,并且, 多个 Route Filter 可以组合实现, 满足我们大多数的处理逻辑

在这里插入图片描述

1.7 自定义 Route Filter

创建AuthGatewayFilterFactory 认证filter工厂


@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {
    

    public AuthGatewayFilterFactory() {
    
        super(AuthGatewayFilterFactory.Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
    
        Map<String, Integer> tokenMap = new HashMap<>();
        tokenMap.put("gss", 1);
        // 创建 gatewayfilter 对象
        return new GatewayFilter() {
    
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
                ServerHttpRequest request = exchange.getRequest();
                HttpHeaders headers = request.getHeaders();
                String token = headers.getFirst(config.getTokenHeaderName());
                // 如果没有 token 不进行认证
                 if (!StringUtils.hasText(token)) {
    
                     return chain.filter(exchange);
                 }
                 // 认证开始
                ServerHttpResponse response = exchange.getResponse();
                Integer userId = tokenMap.get(token);
                // 通过 token 获取不到 userId 说明认证不通过
                if (userId == null) {
    
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    DataBuffer wrap = exchange.getResponse().bufferFactory().wrap("认证未通过".getBytes());
                    return response.writeWith(Flux.just(wrap));
                }
                request = request.mutate().header(config.getUserIdHeaderName(), String.valueOf(userId)).build();
                return chain.filter(exchange.mutate().request(request).build());
            }
        };
    }

    public static class Config {
    

        private static final String DEFAULT_TOKEN_HEADER_NAME = "token";

        private static final String DEFAULT_HEADER_NAME = "user-id";

        private String tokenHeaderName = DEFAULT_TOKEN_HEADER_NAME;
        private String userIdHeaderName = DEFAULT_HEADER_NAME;

        public static String getDefaultTokenHeaderName() {
    
            return DEFAULT_TOKEN_HEADER_NAME;
        }

        public static String getDefaultHeaderName() {
    
            return DEFAULT_HEADER_NAME;
        }

        public String getTokenHeaderName() {
    
            return tokenHeaderName;
        }

        public void setTokenHeaderName(String tokenHeaderName) {
    
            this.tokenHeaderName = tokenHeaderName;
        }

        public String getUserIdHeaderName() {
    
            return userIdHeaderName;
        }

        public void setUserIdHeaderName(String userIdHeaderName) {
    
            this.userIdHeaderName = userIdHeaderName;
        }
    }
}

通过@Compoent 注解 保证 Gateway 在加载所有的 GatewayFilterFactory Bean 的时候,能够加载到我们的自定义AuthGatewayFilterFactory , 有没有发现和自定义断言的时候 一毛一样 哈哈哈
继承 AbstractGatewayFilterFactory 抽象类。 并将泛型参数<C> 设置为我们自己定义的 AuthGatewayFilterFactory.Config 配置类, 这样,Gateway 在解析的时候,会转换成 Config 对象
注意:在AuthGatewayFilterFactory 构造方法中,需要传递 Config 类给父级构造方法,保证能够正确创建出Config 对象。在Config 类中我们定义了两个属性。
- tokenHeaderName : 认证token 的 header 的名字, 默认值为 token
- userIdHeaderName : 认证后的UserId 的 header 名字, 默认为 user-id
在方法 apply(Config config) 中, 我们通过内部类定义了需要创建的GatewayFilter。

1.8 配置 yml 文件

spring:
  cloud:
    gateway:
      default-filters: 
        - name: Auth
          args: 
            token-header-name: access-token

spring.cloud.gateway.default-filters 配置项, Gateway 默认过滤器,对所有的路由都生效。对应 FilterDefinition 数组, 在这里我们配置之了一个自定义的 Filter 配置
- name: 过滤器名称,这里我们设置为Auth, 因为 Gateway 默认使用的 XXXGatewayFilterFactory 的前缀 XXX 名字。 因为 AuthGatewayFilterFactory 就是 Auth
- args: 过滤器的参数配置, 对应 Config 类,这里我们设置 token-header-name 配置项 access-token , 表示从请求头 access-token 中获取认证 token

1.9 简单测试

使用 PostMan 请求接口
在这里插入图片描述
使用 access-token 为 gss 时候
在这里插入图片描述

2.0 请求限流

Gateway 内置 RequestRateLimiterGatewayFilterFactory 提供请求限流功能。 该 Filter 是基于 Token Bucket Algorithm 令牌桶算法。 同时搭配 redis 实现分布式限流。
在这里插入图片描述
限流需要使用到 redis 我们先启动一下 redis, 然后引入redis 的依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

配置 yml 文件

spring:
  redis: 
	host: 127.0.0.1
	port: 6379
  cloud:
    gateway:
      default-filters:
        - name: Auth
          args:
            token-header-name: access-token
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1 # 令牌桶的每秒放的数量
            redis-rate-limiter.burstCapacity: 2 # 令牌桶的最大令牌数
            key-resolver: "#{@ipKeyResolver}" # 获取限流key 的bean 的名字

说一下。 yml 文件配置是增量的。 在上面的基础上添加。 不是删除掉。在添加这个

再次添加一个 default-filters 配置项 。 添加了限流过滤器 RequestRateLimiter 配置参数:
- redis-rate-limiter.replenishRate: 1 # 令牌桶的每秒放的数量
- redis-rate-limiter.burstCapacity: 2 # 令牌桶的最大令牌数
- key-resolver: 获取限流key 的Bean 的名字

burstCapacity 参数: 可以理解为每秒最大的请求数,因此每请求一次,都会从桶里获取一块令牌
ReplenishRate 参数: 可以近似理解为每秒平均的请求数,如果令牌桶为空的情况下,一秒最多放这么多令牌书, 所以最大请求数当然也是这么多
实际上,在令牌桶满的情况下, 每秒最大请求书是 burstCapacity + ReplenishRate

在 GatewayConfig 配置类下创建获取限流Key 的Bean

    @Bean
    public KeyResolver ipKeyResolver(){
    
        return new KeyResolver() {
    
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
    
                return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
            }
        };
    }

创建的 ipKeyResolver Bean 是通过解析请求的来源 IP 作为限流 KEY,这样我们就能实现基于 IP 的请求限流。我们想要实现基于用户的请求限流,那么我们可以创建从请求中解析用户身份的 KeyResolver Bean。也就是说,通过自定义的 KeyResolver 来实现不同粒度的请求限流

2.1 简单测试

使用浏览器,疯狂访问 http://localhost:9527/SGG-PAYMENT-SERVICE/payment/1 就会被限流。 出现 429 页面。
在这里插入图片描述

2.2 基于Hystrix 实现服务容错

引入依赖

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

创建 FallbackController ,提供 /fallback 接口。 用于Hystrix fallback 的重定向。

@RestController
@Slf4j
public class FallbackController {
    

    @GetMapping(value = "fallback")
    public String fallback(ServerWebExchange exchange) {
    
        Object requestURL = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        Object error = exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR);
        log.error("fallback 发生异常: [ {} ], [ {} ]", error, requestURL);
        return "服务降级。。。" + error;
    }
}

通过 exchange.getAttribute(ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR) 可以获取具体的fallback 异常。
配置 yml 文件

spring:
  redis: 
	host: 127.0.0.1
	port: 6379
  cloud:
    gateway:
      default-filters:
        - name: Hystrix
          args:
            name: fallbackcmd # 对应 Hystrix Command 名字
            fallbackUri: forwad:/fallback # 处理 Hystrix fallback 的情况, 重定向到指定地址

在 filters 中配置项,添加了 Hystrix 过滤器。 其配置参数如下。:

  • name: 对应的 Hystrix Command 名字,后续可以通过 hystrix.command.{name} 配置项, 来设置 name 对应的 Hystrix Command 的配置, 比如说超时时间,隔离策略等。
  • fallbackUri: 处理 Hystrix fallback 的情况。 重定向到指定地址,主要 要么为空 要么必须以forward: 开头

2.3 接口测试

在这里插入图片描述
访问 timeout 超时接口。 可以看到出现异常了就会转发到我们的 fallback

2.4 GlobalFilter

在Gateway 中, 有两类过滤器
- Route Filter 路由过滤器 对应GatewayFilter 接口
- Global Filter 全局过滤器 对应 GlobalFilter 接口
两者基本是等价的,不同的是 Route Filter不是全局,可以配置在 指定路由上。 绝大多数情况, RouteFilter 能满足我们的拓展需求的情况下,优先使用它, 并且如果想要作用到所有的路由上。可以使用 spring.cloud.gateway.default-filters 配置上。另外 Global Filter 可能在未来的版本有一定的变化。

Gateway的过滤器的执行分成了前置 pre 和 后置 post 两个阶段,其中低排序值的过滤器在pre 阶段先执行, 高排序值得过滤器在post阶段限制性。 示例代码 。 创建了三个 filter

@Component
@Order(1)
@Slf4j
public class FGlobalFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
        log.info("[F, [pre]]");
        return chain.filter(exchange).then(Mono.<Void>fromRunnable(()->log.info("[F, [post]]")));
    }
}

@Component
@Order(2)
@Slf4j
public class SGlobalFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
        log.info("[S, [pre]]");
        return chain.filter(exchange).then(Mono.<Void>fromRunnable(()->log.info("[S, [post]]")));
    }
}

@Component
@Order(3)
@Slf4j
public class TGlobalFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
        log.info("[T, [pre]]");
        return chain.filter(exchange).then(Mono.<Void>fromRunnable(()->log.info("[T, [post]]")));
    }
}

重启接口,发现打印和我们之前说的一样

2020-09-13 01:24:05.068  INFO 16968 --- [ioEventLoop-4-1] cn.fllday.filter.FGlobalFilter           : [F, [pre]]
2020-09-13 01:24:05.070  INFO 16968 --- [ioEventLoop-4-1] cn.fllday.filter.SGlobalFilter           : [S, [pre]]
2020-09-13 01:24:05.070  INFO 16968 --- [ioEventLoop-4-1] cn.fllday.filter.TGlobalFilter           : [T, [pre]]
2020-09-13 01:24:05.198  INFO 16968 --- [ctor-http-nio-4] cn.fllday.filter.TGlobalFilter           : [T, [post]]
2020-09-13 01:24:05.198  INFO 16968 --- [ctor-http-nio-4] cn.fllday.filter.SGlobalFilter           : [S, [post]]
2020-09-13 01:24:05.198  INFO 16968 --- [ctor-http-nio-4] cn.fllday.filter.FGlobalFilter           : [F, [post]]

2.4 Gateway 监控端点

Gateway的 actuate 模块, 基于 SpringBoot Actuator , 提供了 自动以监控断点 gateway, 提供了 Gateway 的各种监控管理的功能

路径 用途
GET /globalfilters 获取所有的 GlobalFilter
GET /routefilters 获取所有GatewayFilterFactory
GET /routepredicates 后去所有的RoutePredicateFactory
GET /routes 获取所有的路由
GET /routes/{id} 获取指定路由
GET /routes/{id}/combinedfilters 获得指定路由的过滤器
POST /routes/{id} 新增或修改,参数为 RouteDefinition
DELETE /routes/{id} 删除指定路由
POST /refresh 刷新路由缓存

注意: 所有的基础路径为 /actuator/gateway,所以 /globalfilters 对应的完整路径是 /actuator/gateway/globalfilters

引入 pom 依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

修改 yml 文件 , 配置 Spring Boot Actuator

management:
  endpoints:
    web:
      exposure:
        include: '*' # 需要开放的端点,默认只开放 health 和 info 两个端点,通过 * 开放所有的端点。
  endpoint:
    health:
      enabled: true  # 是否开启, 默认true 开启
      show-details: always # 何时显示完整的健康信息。 默认 never 都不展示。 可选择 WHEN_AUTHORIZED 当经过授权的用户, 可选 always 总是显示

获取 filter 和 predicate
GlobalFilter: http://localhost:9527/actuator/gateway/globalfilters
在这里插入图片描述
GatewayFilterFactory: http://localhost:9527/actuator/gateway/routefilters在这里插入图片描述
Predicates: http://localhost:9527/actuator/gateway/routepredicates
在这里插入图片描述
路由管理
使用 PostMan 请求GET /actuator/gateway/routes/{id} 获取一个路由详情
在这里插入图片描述
然后根据这个 我们新建一个路由
POST /actuator/gateway/routes/{id}
在这里插入图片描述
添加完成之后,我们通过 使用 PostMan 请求GET /actuator/gateway/routes/baidutieba 获取一个路由详情
在这里插入图片描述
如果不行的话,记得使用refresh 刷新一下 POST /actuator/gateway/refresh
然后不要重启服务。 直接访问 http://localhost:9527/ 就会直接跳转到百度贴吧咯
在这里插入图片描述

2.6 日志级别

修改 yml 文件。配置日记级别如下

logging:
  level: 
    reactor.netty: DEBUG
    org.springframework.cloud.gateway: TRACE

这样,SpringCloudGateway 和 Reactor Netty 可以打印更多的日志
重启网关。
在这里插入图片描述
Gateway日志。 其他 Reactor Netty 日志太多。 就不截图了。

27 Wiretap

Reactor Netty 提供了 Wiretap 窃听功能。 让 Reactor Netty 打印包含请求和响应信息的日志, 比如说请求和响应的Header Body 等等, 开启 Reactor Netty 的Wiretap 功能一共有三个配置项

  • 设置 reactor.netty 的配置项为DEBUG 和 TRACE
  • 设置 spring.cloud.gateway.httpserver.wiretap 配置项为 true 开启 HttpServer Wiretap 功能
  • 设置 spring.cloud.gateway.httpclient.wiretap 配置项为 true 开启 Http Client wiretap 功能
      httpserver: # 配置 Reactor Netty 相关配置
        wiretap: true
      httpclient:
        wiretap: true

好多东西。截图放着了。
在这里插入图片描述

总结

感谢B站尚硅谷老师哈哈 ~~~ 本文参考了
芋道源码 感谢!@!!
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40990836/article/details/108544521

智能推荐

解决create-react-app在ie中打开页面空白的兼容性问题_react ie浏览器下路由视图空白-程序员宅基地

文章浏览阅读6.9k次。最近使用react官方脚手架create-react-app建立项目的时候发现在ie浏览器打开时显示空白,在主流的chrome、fireFox等浏览器显示是正常的。打开控制台显示如下既然提示了语法错误,那么猜想应该是兼容性的问题,看了下浏览器的版本号是ie11。首先我翻了下create-react-app的文档,从中看到了正好有对ie9、ie10、ie11的兼容性问题解决的一个方案。这时需要..._react ie浏览器下路由视图空白

基于SSM的网盘管理系统的设计与实现_ssm实现网盘功能-程序员宅基地

文章浏览阅读122次。网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。因此文件信息的管理计算机化,系统化是必要的。设计开发网盘管理系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于文件信息的维护和检索也不需要花费很多时间,非常的便利。网盘管理系统是在MySQL中建立数据表保存信息,运用Vue框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。_ssm实现网盘功能

Elastic-job 与 xxl-job 任务调度框架_xxljob elsticjob-程序员宅基地

文章浏览阅读2k次。#xxl-job文档地址1.https://www.xuxueli.com/xxl-job/#Elastic-job 文档地址2.http://elasticjob.io/index_zh.html3.建议使用xxl-job,原因如下:偏重量级框架; 依赖Spring,mysql,maven手动编译; 提供的demo众多; GUI编写任务代码; GUI发布任务; 提供..._xxljob elsticjob

iOS 开发中的小技巧-程序员宅基地

文章浏览阅读94次。http://nshipster.cn转载于:https://www.cnblogs.com/Seeulater/p/5236805.html

【DenseFusion代码详解】linemod数据集预处理过程_line mod 数 据集-程序员宅基地

文章浏览阅读3.2k次,点赞8次,收藏25次。这里分析linemod数据集预处理的代码,位置在datasets/linemod/dataset.py我们一行一行的分析。import torch.utils.data as dataclass PoseDataset(data.Dataset): def __init__(self, mode, num, add_noise, root, noise_trans, refine): self.objlist = [1, 2, 4, 5, 6, 8, 9, 10, 11,_line mod 数 据集

Andorid 流式布局 热门标签解决方案_andorid 使用流式布局实现便签页面-程序员宅基地

文章浏览阅读972次。// 流式布局 话不多说,比较简单,注释都写的很清楚import java.util.ArrayList;import java.util.List;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGr_andorid 使用流式布局实现便签页面

随便推点

php手册chm打开空白_php chm没有内容-程序员宅基地

文章浏览阅读1.6k次。chm手册打开空白的解决方法_php chm没有内容

视觉SLAM中ORB特征点算法(关键点+描述子)-程序员宅基地

文章浏览阅读1.4k次。特征点是什么SLAM需要根据路标来计算当前相机的位置和姿态。而视觉SLAM的路标就是图像中的特征点了。注意:只要谈到图像中的特征点你就得记得它包含两个内容关键点和描述子。关键点指的特征点在图像中的位置,而描述子是指的是关键点的朝向和周围像素信息。相同特征..._orbslam特征点 描述子

类集面试题(二)HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别_hashmap和treemap和hashtable的区别 面试题-程序员宅基地

文章浏览阅读603次。文章目录Java为数据结构中的映射定义了一个接口java.util.Map。它包含三个类:HashMap、HashTable和TreeMap。Map是用来存储键值对的数据结构,在数组中通过数组下标来对其内容索引的,而在Map中,则是通过对象进行索引,用来索引的对象称作是Key,其对应的对象叫做value。HashMap是最常用的Map,它根据键值对的HashCode值存储数据,根据键可以直接获..._hashmap和treemap和hashtable的区别 面试题

模型中AIC和BIC以及loglikelihood的关系_log likelihood越大越好还是越小越好-程序员宅基地

文章浏览阅读7.9k次,点赞7次,收藏63次。asreml中,用于比较模型的LRT检验,会给出P值,但是这只能表示两个模型达到显著与否,而不能表示哪个模型优秀。常用的参数有AIC,BIC,loglikelihood,本篇介绍一下这几个参数的含义,以及是如何计算的1. AIC的解释赤池信息准则(Akaike Information Criterion,AIC)AIC是衡量统计模型拟合优良性的一种标准,由日本统计学家赤池弘次在1974年提出,它建立在熵的概念上,提供了权衡估计模型复杂度和拟合数据优良性的标准。通常情况下,AIC定义为:AIC=−2_log likelihood越大越好还是越小越好

注解WebServlet配置Servlet报404错误的原因-程序员宅基地

文章浏览阅读1.1k次。使用注解WebServlet配置Servlet报404错误的原因 Servlet3.0之后新增了注解,用于简化Servlet、Filter及Listener的声明,这样就在配置Servlet的时候多了一个选择。Servlet3.0的部署描述文件web.xml的顶层标签<web-app>有一个metadata-complete属性,该属性为true,则容器在部署时只依赖部..._servlet 注释 远程404

关于for (i = (n|1)-2; i > 0; i-=2)_$j=2; for( $i=7; $i>0; $i-=2 ){ $j*=2;}-程序员宅基地

文章浏览阅读321次。对于奇偶有了更好的写法,如果是偶数i=n+1,如果是奇数就为i=n_$j=2; for( $i=7; $i>0; $i-=2 ){ $j*=2;}

推荐文章

热门文章

相关标签