springcloud-网关(gateway)
springcloud-网关(gateway)
概述
\Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为其提供跨领域的关注,如:安全、监控/指标和容错
常用术语
- Route(路由): 网关的基本构件。它由一个ID、一个目的地URI、一个谓词(Predicate)集合和一个过滤器(Filter)集合定义。如果集合谓词为真,则路由被匹配。
- Predicate(谓词): 这是一个 Java 8 Function Predicate。输入类型是 [Spring Framework ServerWebExchange]。这让你可以在HTTP请求中的任何内容上进行匹配,比如header或查询参数。
- Filter(过滤器): 这些是 [GatewayFilter] 的实例,已经用特定工厂构建。在这里,你可以在发送下游请求之前或之后修改请求和响应。
网关工作原理
客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配,它将被发送到Gateway Web处理程序。这个处理程序通过一个特定于该请求的过滤器链来运行该请求。过滤器被分割的原因是,过滤器可以在代理请求发送之前和之后运行逻辑。所有的
"pre"
(前)过滤器逻辑都被执行。然后发出代理请求。在代理请求发出后,"post"
(后)过滤器逻辑被运行。
业务架构图
开发流程
引入依赖
gateway框架需要引入loadbalancer,否则在访问的时候会出现503异常。
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
bootstrap.yml配置
配置nacos
如果不需要nacos的配置,可以不引入nacos的config依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:application:name: ssc-cloud-gatewaycloud:nacos:discovery:server-addr: 192.168.201.81:7777namespace: ssc-cloud-idgroup: DEVregister-enabled: true
配置gateway
spring:cloud:gateway:discovery:locator:enabled: trueroutes:- id : ssc-order-id #路由编号(自定义)
# uri: https://www.bilibili.com/ #跳转地址(网页跳转),lb--负载调整(微服务)uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/** #url 的映射名称(让客户看到的)filters:- StripPrefix=1- id: ssc-paycenter-id #路由编号(自定义)uri: lb://ssc-cloud-paycenterpredicates:- Path=/ssc-pay/**filters:- StripPrefix=1
路由配置规则
序号 | 名称 | 解释 |
---|---|---|
1 | id | ⾃定义的路由 ID,保持唯⼀ |
2 | uri | 目标服务地址:以lb:// 开头则表示要去向的微服务名称 |
3 | predicates | 路由条件 |
4 | Filter(过滤器) | 过滤器是路由转发请求时所经过的过滤逻辑,可⽤于修改请求、响应内容。 |
predicates断言条件
-
Path
实例: - Path=/ssc-older/
routes:- id : ssc-older-id uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/**
解释: 当请求的路径为ssc-older开头的时,转发到ssc-cloud-older微服服务器上,ssc-cloud-older是navcos中微服务注册的名称。
-
Before
- Before=2017-01-20T17:42:47.789-07:00[Asia/Shanghai]
在某个时间之前的请求才会被转发到 http://localhost:9001 服务器上
-
After
- After=2017-01-20T17:42:47.789- 07:00[Asia/Shanghai]
在某个时间之后的请求才会被转发
-
Between
- Between=2017-01-20T17:42:47.789-07:00[Asia/Shanghai],
2017-01- 21T17:42:47.789-07:00[Asia/Shanghai]
在某个时间段之间的才会被转发
-
Cookie
- Cookie=sesionId,ssc-test
名为ss-old的表单或者满⾜正则old的表单才会被匹配到 进⾏请求转发
routes:- id : ssc-older-id uri: lb://ssc-cloud-olderpredicates:- Cookie=sesionId,ssc-test
-
Header
- Header=X-Request-Id
携带参数X-Request-Id的请求头才会匹配
-
Host
- Host=www.ssc.older.com
当主机名为www.ssc.older.com的时候直接转发到指定服务器。
-
Method
- Method=GET
只有GET⽅法才会匹配转发请求,还可以限定POST、PUT等。
routes:- id : ssc-older-id uri: lb://ssc-cloud-olderpredicates:- Method=GET,POST
过滤器规则
过滤规则 | 实例 | 说明 |
---|---|---|
PrefixPath | - PrefixPath=/app | 在请求路径前加上app |
PrefixPath | - PrefixPath=/app | 在请求路径前加上app |
SetPath | SetPath=/app/{path} | 通过模板设置路径,转发的规则时会在路径前增加 app,{path}表示原请求路径 |
RedirectTo | 重定向 | |
RemoveRequestHea | 去掉某个请求头信息\1. PrefixPath | |
StripPrefix | Path=/ssc-pay/** | 去掉ssc-pay才是真实路径 |
网关的案例
使用网关进行用户鉴权过滤。
鉴权微服务
api模块
api模块为外界提供接口(openfeign调用),为网关调用需要基于reactor开发。
pom
<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.wnhz.ssc.cloud.authority</groupId><artifactId>ssc-cloud-authority</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.wnhz.ssc.cloud.authority.api</groupId><artifactId>ssc-cloud-authority-api</artifactId><dependencies><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-webclient</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-cloud</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-spring-configuration</artifactId><version>3.0.3</version></dependency></dependencies>
</project>
openfeign接口
@ReactiveFeignClient(value = "ssc-cloud-authority",url = "http://localhost:12121")
public interface IAuthorityFeign {@GetMapping("/api/authority/login")Mono<HttpResp> login(@RequestParam("username") String username,@RequestParam("password") String password);@PostMapping("/api/authority/verifyToken")Mono<HttpResp> verifyToken(String token);
}
业务接口(sevice)
pom.xml
<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.wnhz.ssc.cloud.authority</groupId><artifactId>ssc-cloud-authority</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.wnhz.ssc.cloud.authority.service</groupId><artifactId>ssc-cloud-authority-service</artifactId><dependencies><dependency><groupId>com.wnhz.ssc.cloud.springcloud</groupId><artifactId>ssc-cloud-springcloud</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId></dependency><dependency><groupId>com.wnhz.ssc.cloud</groupId><artifactId>ssc-cloud-tools</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.wnhz.ssc.cloud</groupId><artifactId>ssc-cloud-ssm</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies>
</project>
配置
bootstrap.yml
spring:cloud:nacos:config:server-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}file-extension: yamlextension-configs:- data-id: db_ssc.yamlgroup: DEVrefresh: true- data-id: redis.yamlgroup: DEVrefresh: truediscovery:server-addr: 192.168.201.107namespace: ssc-cloud-idgroup: DEVapplication:name: ssc-cloud-authority
application
-
application-dev.yml
server:port: 12121 knife4j:enable: true logging:level:com.wnhz: debug
-
application.yml
spring:profiles:active: dev
启动类
@EnableDiscoveryClient
@SpringBootApplication
public class AuthorityApp {public static void main(String[] args) {SpringApplication.run(AuthorityApp.class);}
}
dao
@Mapper
public interface ILoginDao extends BaseMapper<Login> {
}
异常
/*** 鉴权异常*/
public class AuthorityException extends RuntimeException{public AuthorityException(String message) {super(message);}
}
/*** 用户名或密码错误异常*/
public class BadCredentialsException extends AuthorityException{public BadCredentialsException(String message) {super(message);}
}
service
-
接口
public interface ILoginService {Login loginCheck(String username, String password);List<Login> findByUsername(String username); }
-
实现类
package com.wnhz.ssc.cloud.authority.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.wnhz.ssc.cloud.authority.dao.ILoginDao; import com.wnhz.ssc.cloud.authority.exception.BadCredentialsException; import com.wnhz.ssc.cloud.authority.exception.UsernameEmptyException; import com.wnhz.ssc.cloud.authority.exception.UsernameNotFoundException; import com.wnhz.ssc.cloud.authority.service.ILoginService; import com.wnhz.ssc.domain.entity.po.Login; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils;import java.util.List; import java.util.Objects;@Service public class LoginServiceImpl implements ILoginService {@Autowiredprivate ILoginDao loginDao;@Overridepublic Login loginCheck(String username, String password) {if (!StringUtils.hasText(username)) throw new UsernameEmptyException("用户名为空异常");LambdaQueryWrapper<Login> lambdaQueryWrapper= new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(Login::getUsername, username);List<Login> logins = findByUsername(username);Login login = logins.stream().filter(lg -> username.equals(lg.getUsername())).findFirst().get();if (Objects.isNull(login)) throw new BadCredentialsException("用户名|密码错误");return login;}/*** 判读用户名是否存在* @param username 用户名* @return 所有查询服务用户名的用户集合*/@Overridepublic List<Login> findByUsername(String username) {List<Login> logins = loginDao.selectList(new LambdaQueryWrapper<Login>().eq(Login::getUsername, username));if (Objects.isNull(logins) || logins.isEmpty()) throw new UsernameNotFoundException("用户名不存在异常");return logins;} }
controller
package com.wnhz.ssc.cloud.authority.controller;import com.wnhz.ssc.cloud.authority.service.ILoginService;
import com.wnhz.ssc.cloud.tools.exception.jwt.JwtException;
import com.wnhz.ssc.cloud.tools.exception.jwt.JwtExpiredException;
import com.wnhz.ssc.cloud.tools.jwt.JwtUtil;
import com.wnhz.ssc.common.result.HttpResp;
import com.wnhz.ssc.domain.entity.po.Login;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Api(tags = "鉴权模块api")
@RestController
@RequestMapping("/api/authority")
@Slf4j
public class AuthorityController {@Autowiredprivate ILoginService loginService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;private final String REDIS_PREFIX="token:";/*** 用户登录** @param username* @param password* @return*/@ApiOperation(value = "login", notes = "用户登录验证")@GetMapping("/login")public HttpResp login(String username, String password) {try {Login login = loginService.loginCheck(username, password);log.debug("用户名登录成功:{}",login);Map<String, Object> map = new HashMap<>();map.put("username", username);String token = JwtUtil.getInstance().creatToken(map, 1000 * 30, login.getSign());stringRedisTemplate.opsForValue().set(REDIS_PREFIX+token, login.getSign(),10, TimeUnit.MINUTES);log.debug("token产生成功,并存入redis中:{}",token);return HttpResp.success(new String[]{"ssc_login_token", token});} catch (Exception e) {return HttpResp.failed(e.getMessage());}}/*** 验证token** @param token* @return*/@ApiOperation(value = "verifyToken", notes = "token验证")@GetMapping("/verifyToken")public Mono<HttpResp> verifyToken(String token) {String sign = stringRedisTemplate.opsForValue().get(REDIS_PREFIX+token);log.debug("从redis中获取token的值: {}", sign);if (Objects.isNull(sign)) {return Mono.just(HttpResp.failed("token不存在"));}try {JwtUtil.getInstance().verifyToken(token, sign);return Mono.just(HttpResp.success("token验证成功"));} catch (JwtExpiredException e) {//token已过期,判断是否续期return refreshToken(token, sign);} catch (JwtException e) {return Mono.just(HttpResp.failed(e.getMessage()));}}private Mono<HttpResp> refreshToken(String originalToken, String sign) {Long expireLeftTime = stringRedisTemplate.getExpire(REDIS_PREFIX+originalToken);log.debug("redis中token剩余时间:{}", expireLeftTime);if (expireLeftTime > 0) {//token续期String newToken = JwtUtil.getInstance().cloneToken(originalToken, expireLeftTime);stringRedisTemplate.delete(REDIS_PREFIX+originalToken);stringRedisTemplate.opsForValue().set(REDIS_PREFIX+newToken, sign);log.debug("新token产生成功,续期完成,token==> {}",newToken);return Mono.just(HttpResp.success(new String[]{"ssc_login_token", newToken}));} //token已经过期,redis也过期return Mono.just(HttpResp.failed("token已经过期"));}
}
全局网关
负责对鉴权控制
pom
<?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>wnhz-ssc-cloud</artifactId><groupId>com.wnhz.ssc.cloud</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.wnhz.ssc.cloud.gateway</groupId><artifactId>ssc-cloud-gateway</artifactId><dependencies><dependency><groupId>com.wnhz.ssc.cloud.springcloud</groupId><artifactId>ssc-cloud-springcloud</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.wnhz.ssc.cloud.common</groupId><artifactId>ssc-cloud-common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-spring-configuration</artifactId><version>3.0.3</version><scope>compile</scope></dependency><dependency><groupId>com.wnhz.ssc.cloud.authority.api</groupId><artifactId>ssc-cloud-authority-api</artifactId><version>0.0.1-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><outputDirectory>../out</outputDirectory></configuration></plugin></plugins></build>
</project>
配置
bootstrap.yml
spring:main:web-application-type: reactiveapplication:name: ssc-cloud-gatewaycloud:nacos:discovery:server-addr: 192.168.201.81:7777namespace: ssc-cloud-idgroup: DEVregister-enabled: trueconfig:enabled: offgateway:discovery:locator:enabled: trueroutes:- id : ssc-order-id #路由编号(自定义)
# uri: https://www.bilibili.com/ #跳转地址(网页跳转),lb--负载调整(微服务)uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/** #url 的映射名称(让客户看到的)filters:- StripPrefix=1- id: ssc-paycenter-id #路由编号(自定义)uri: lb://ssc-cloud-paycenterpredicates:- Path=/ssc-pay/**filters:- StripPrefix=1- id: ssc-authority-id #路由编号(自定义)uri: lb://ssc-cloud-authoritypredicates:- Path=/ssc-auth/**filters:- StripPrefix=1
全局过滤器
package com.wnhz.ssc.cloud.gateway.filter;import com.fasterxml.jackson.databind.ObjectMapper;
import com.wnhz.ssc.cloud.authority.feign.IAuthorityFeign;
import com.wnhz.ssc.common.result.HttpResp;
import com.wnhz.ssc.common.result.RespCode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;@Component
@Slf4j
public class SscGlobalGatewayFilter implements GlobalFilter, Ordered {@Lazy@Autowiredprivate IAuthorityFeign authorityFeign;private final String LOGIN_TOKEN="ssc_login_token";@SneakyThrows@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();log.debug("我进入过滤中.....");ObjectMapper objectMapper = new ObjectMapper();DataBuffer dataBuffer = null;String requestURI =request.getURI().getPath() ;log.debug("请求uri:{}",requestURI);if(requestURI.endsWith("/authority/login")){//客户访问登录业务,直接跳转验证return chain.filter(exchange);}//1. Token不存在,客户未登录状态访问系统if(!isLogin(request)) {//如果客户没有登录log.debug("客户还没有登录,重定向到登录(baidu)页面");String redirectUrl = "https://www.baidu.com";log.debug("将客户请求重定向到指定页面: {}", redirectUrl);response.getHeaders().set(HttpHeaders.LOCATION, redirectUrl);//303状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源response.setStatusCode(HttpStatus.SEE_OTHER);response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");return response.setComplete();}//2. token存在,调用验证微服务验证token是否有效String token = getToken(request);HttpResp block = authorityFeign.verifyToken(token).block();if(block.getCode()== RespCode.FAILED.getCode()){ //token验证失败response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");dataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsString(block).getBytes(StandardCharsets.UTF_8));return response.writeWith(Mono.just(dataBuffer));}return chain.filter(exchange);}@Overridepublic int getOrder() {return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;}/*** 客户未登录,没有token* @param request* @return*/private boolean isLogin(ServerHttpRequest request){HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> loginToken = headers.get(LOGIN_TOKEN);if(Objects.nonNull(loginToken)){return true;}return false;}/*** 从请求中获取token* @param request*/private String getToken(ServerHttpRequest request){HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> tokens = headers.get(LOGIN_TOKEN);String token = tokens.get(0);return token;}
}
启动类
package com.wnhz.ssc.cloud.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import reactivefeign.spring.config.EnableReactiveFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableReactiveFeignClients(basePackages = "com.wnhz.ssc.cloud.authority.feign")
public class GatewayApp {public static void main(String[] args) {SpringApplication.run(GatewayApp.class);}
}
HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> tokens = headers.get(LOGIN_TOKEN);String token = tokens.get(0);return token;
}
}
### 启动类```java
package com.wnhz.ssc.cloud.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import reactivefeign.spring.config.EnableReactiveFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableReactiveFeignClients(basePackages = "com.wnhz.ssc.cloud.authority.feign")
public class GatewayApp {public static void main(String[] args) {SpringApplication.run(GatewayApp.class);}
}
相关文章:

springcloud-网关(gateway)
springcloud-网关(gateway) 概述 \Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为其提供跨领域的关注,如:安全、监控/指标和容错 常用术语 Route(路由): 网关的基本构件。它由一个ID、一个目的地…...

2.20 day2 QT
自由发挥登录窗口的应用场景,实现一个登录窗口界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {//窗口相关设置this->setWindowTitle("登入页面"); //设置 窗口 标题this->setWindowIcon(QIcon("D:…...

【C++语法基础】4.分支和循环结构(✨新手推荐阅读)
前言 在C编程中,分支和循环结构是控制程序流程的基本工具。分支结构允许程序根据特定条件执行不同的代码块,而循环结构则允许程序重复执行某个代码块。 分支结构 if 语句 if 语句是最基本的分支结构,它根据条件的真假来决定是否执行某段代…...

朋友圈程序全开源版源码,附带系统搭建教程
前台一键发布图文,视频,音乐。发布内容支持定位或自定义位置信息。支持将发布内容设为广告模式消息站内通知或邮件通知。支持其他用户注册,支持其他用户发布文章,管理自己的文章。拥有丰富的后台管理功能,一键操作。安装环境 Nginx ≥1.22 …...

思维方式系列文章目录 -《清单革命》实践
思维方式系列文章目录 -《清单革命》 文章目录 思维方式系列文章目录 -《清单革命》前言一、《清单革命》思维导图二、清单制作原则 前言 请记住,现在开始心灵转变,人人都会犯错,而错误分为:无知之错、无能之错。 无知之错&#…...
RAID 创建使用以及ubuntu安装和使用zfs文件系统及Ubuntu软件安装
RAID 创建使用 部署 RAID 10 的学习 1. 搭建 RAID 10 就是 RAID 1 加上 RAID 0,准备四块磁盘,用于创建 RAID 10,配置vmware虚拟机,创建四个虚拟硬盘。 2. 检查磁盘信息 rootubuntu:~# ls /dev/sd* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/s…...
yarn常用命令小记
安装 npm install -g yarn查看版本 yarn -v初始化项目与依赖管理 yarn init:与npm init一样通过交互式会话生成一个新的package.jason文件以初始化项目;跳过会话可使用yarn init --yes,简写yarn init -yyarn add <package><versi…...

防御保护---内容保护
文章目录 目录 文章目录 一.防火墙内容安全概述 二.深度识别技术(DFI/DPI) 深度包检测技术(DPI) 深度流检测技术(DFI) 两者区别 三.入侵防御IPS 一.防火墙内容安全概述 防火墙内容安全是防火墙的一个重…...
jquery将网页html文档导出为pdf图片
jquery将网页html文档导出为pdf图片 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…...

opengl 学习着色器
一.GLSL 着色器是使用一种叫GLSL的类C语言写成的。GLSL着色器编码顺序:声明版本》定义输入输出》uniform》main函数。每个着色器的入口点是main函数,在main函数中我们处理所有的输入变量,并将结果输出到输出变量中。如下图: #ver…...

【数据结构】18 二叉搜索树(查找,插入,删除)
定义 二叉搜索树也叫二叉排序树或者二叉查找树。它是一种对排序和查找都很有用的特殊二叉树。 一个二叉搜索树可以为空,如果它不为空,它将满足以下性质: 非空左子树的所有键值小于其根节点的键值非空右子树的所有键值都大于其根结点的键值左…...

力扣日记2.20-【回溯算法篇】491. 非递减子序列
力扣日记:【回溯算法篇】491. 非递减子序列 日期:2023.2.20 参考:代码随想录、力扣 ps:放了个寒假,日记又搁置了三星期……(下跪忏悔) 491. 非递减子序列 题目描述 难度:中等 给你一…...

Android 13.0 SystemUI下拉状态栏定制二 锁屏页面横竖屏解锁图标置顶显示功能实现
1.前言 在13.0的系统rom定制化开发中,在关于systemui的锁屏页面功能定制中,由于在平板横屏锁屏功能中,时钟显示的很大,并且是在左旁边居中显示的, 由于需要和竖屏显示一样,所以就需要用到小时钟显示,然后同样需要居中,所以就来分析下相关的源码,来实现具体的功能 如图…...

FPGA_简单工程_拨码开关
一 框图 二 波形图 三 代码 3.1 工程代码 module bomakiaguan (input [15:0] switch, // 输入16路拨码开关output reg [15:0] led // 输出16个LED灯 );always (switch) beginled < switch; // 将拨码开关的值直接赋给LED灯 end // 将拨码开关的值直接赋给LED灯 endmodu…...

LaunchPad 市场的复苏,Penpad 成新兴生力军
以 Fair Launch 为主要启动方式的铭文市场的爆发,推动了 LaunchPad 市场的复苏,绝多数所铭文项目都能通过 Fairr Launch 的方式筹集资金实现启动,该赛道的爆发不仅推动了数百亿美元的热钱开始在链上不断涌动,同时也进一步形成了新…...

知识图谱实战应用30-基于py2neo的天文学中的恒星、行星与卫星之间的关系知识图谱研究与应用
大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用30-基于py2neo的天文学中的恒星、行星与卫星之间的关系知识图谱研究与应用。本文将详细介绍如何利用py2neo构建天文学中的恒星、行星与卫星之间的关系知识图谱,并探讨其在天文学研究中的应用。文章将提供多条太阳系中恒…...

笔试题详解(C语言进阶)
前言 欢迎阅读本篇文章!本篇文章通过一个笔试题来加强我们对C语言的理解,希望对你有帮助。后续我会写一个栏目,集合我见到的C语言题目,进行分析讲解。 1、题目一 判断下面程序的输出结果:(下面说的地址4/8字节是因为对…...

ClickHouse快速上手
简介 ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS) 官网(https://clickhouse.com/docs/zh)给出的定义,其实没看懂 特性 ClickHouse支持一种基于SQL的声明式查询语言,它在许多情况下与ANSI SQL标准相同。使用时和MySQL有点相似&#…...

蓝桥杯DP算法——背包问题(C++)
目录 一、01背包问题 二、完全背包问题 三、多重背包问题 四、多重背包问题(优化版) 五、分组背包问题 一、01背包问题 01背包问题就是有N件物品,一个空间大小为V的背包,每个物品只能使用一次,使得背包中所装物品…...
【LeetCode+JavaGuide打卡】Day22|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
学习目标: 235. 二叉搜索树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点 学习内容: 235. 二叉搜索树的最近公共祖先 题目链接&&文章讲解 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的 第一部分: 0: kd> g Breakpoint 9 hit Ntfs!ReadIndexBuffer: f7173886 55 push ebp 0: kd> kc # 00 Ntfs!ReadIndexBuffer 01 Ntfs!FindFirstIndexEntry 02 Ntfs!NtfsUpda…...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...