微服务day04
网关


网关路由
快速入门


创建新模块:hm-gateway继承hmall父项目。
引入依赖:引入网关依赖和nacos负载均衡的依赖
<?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.heima</groupId><artifactId>hmall</artifactId><version>1.0.0</version></parent><groupId>com.wmmczk</groupId><artifactId>hm-gateway</artifactId><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--nacos discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
编写配置文件:一个模块中有多个collection类就可以写多个判断路径。
server:port: 8080
spring:application:name: gatewaycloud:nacos:server-addr: 192.168.21.101:8848gateway:routes:- id: item # 路由规则id,自定义,唯一uri: lb://item-service # 路由的目标服务,lb代表负载均衡,会从注册中心拉取服务列表predicates: # 路由断言,判断当前请求是否符合当前规则,符合则路由到目标服务- Path=/items/**,/search/** # 这里是以请求路径作为判断规则- id: carturi: lb://cart-servicepredicates:- Path=/carts/**- id: useruri: lb://user-servicepredicates:- Path=/users/**,/addresses/**- id: tradeuri: lb://trade-servicepredicates:- Path=/orders/**- id: payuri: lb://pay-servicepredicates:- Path=/pay-orders/**
路由属性



网关登陆校验


自定义过滤器


GlobaFilter自定义过滤器

//Ordered接口为spring中的排序接口,为核心接口
//GlobalFilter要在NettyRoutingFilter之前,NettyRoutingFilter的Ordered的值为int的最大值,确保其最后执行
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取requestServerHttpRequest request = exchange.getRequest();//获取header头HttpHeaders headers = request.getHeaders();System.out.println("headers = " + headers);return chain.filter(exchange);//将exchange传给下一个过滤器}@Overridepublic int getOrder() {// 过滤器执行顺序,值越小,优先级越高return 0;}
}
GatewayFilter自定义过滤器

登录校验
JWT工具
登录校验需要用到JWT,而且JWT的加密需要秘钥和加密工具。这些在hm-service中已经有了,我们直接拷贝过来:

具体作用如下:
-
AuthProperties:配置登录校验需要拦截的路径,因为不是所有的路径都需要登录才能访问 -
JwtProperties:定义与JWT工具有关的属性,比如秘钥文件位置 -
SecurityConfig:工具的自动装配 -
JwtTool:JWT工具,其中包含了校验和解析token的功能 -
hmall.jks:秘钥文件
其中AuthProperties和JwtProperties所需的属性要在application.yaml中配置
hm:jwt:location: classpath:hmall.jks # 秘钥地址alias: hmall # 秘钥别名password: hmall123 # 秘钥文件密码tokenTTL: 30m # 登录有效期auth:excludePaths: # 无需登录校验的路径- /search/**- /users/login- /items/**
创建自定义拦截器:
package com.hmall.gateway.Filte;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.AntPathMatcher;
import com.hmall.common.exception.UnauthorizedException;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.util.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
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.util.List;@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {//用于读取配置文件中要放行的路径private final AuthProperties authProperties;private final AntPathMatcher antPathMatcher = new AntPathMatcher();private final JwtTool jwtTool;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取requsetServerHttpRequest request = exchange.getRequest();//获取path进行判断是否需要拦截RequestPath path = request.getPath();//使工具类进行判断if (isPath(path)){//放行return chain.filter(exchange);}//获取tokenString token = null;HttpHeaders headers = request.getHeaders();List<String> list = headers.get("Authorization");if (!CollUtil.isEmpty(list)){//给token赋值token = list.get(0);}//校验tokenLong userId = null;try {userId = jwtTool.parseToken(token);} catch (UnauthorizedException e) {//token无效进行拦截//获取Response进行编辑ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();//该状态可以使后面的过滤器不在执行,返回错误}//TODO 传递用户信息System.out.println("userId = " + userId);return chain.filter(exchange);}private boolean isPath(RequestPath path) {//转为String类型String string = path.toString();//将配置文件中定义的路径进行遍历for (String excludePath : authProperties.getExcludePaths()) {if (antPathMatcher.match(excludePath, string)){//使用工具类进行匹配 antPathMatcher.match ,匹配成功返回truereturn true;}}return false;}@Overridepublic int getOrder() {return 0;}
}
网关传递用户信息


//TODO 传递用户信息String userinfo = userId.toString();//exchange提供了修改请求头信息的方法mutateServerWebExchange build = exchange.mutate().request(b -> b.header("user-info",userinfo)).build();System.out.println("userId = " + userId);return chain.filter(build);
package com.hmall.gateway.Filte;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.AntPathMatcher;
import com.hmall.common.exception.UnauthorizedException;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.util.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
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.util.List;@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {//用于读取配置文件中要放行的路径private final AuthProperties authProperties;private final AntPathMatcher antPathMatcher = new AntPathMatcher();private final JwtTool jwtTool;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取requsetServerHttpRequest request = exchange.getRequest();//获取path进行判断是否需要拦截RequestPath path = request.getPath();//使工具类进行判断if (isPath(path)){//放行return chain.filter(exchange);}//获取tokenString token = null;HttpHeaders headers = request.getHeaders();List<String> list = headers.get("Authorization");if (!CollUtil.isEmpty(list)){//给token赋值token = list.get(0);}//校验tokenLong userId = null;try {userId = jwtTool.parseToken(token);} catch (UnauthorizedException e) {//token无效进行拦截//获取Response进行编辑ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();//该状态可以使后面的过滤器不在执行,返回错误}//TODO 传递用户信息String userinfo = userId.toString();//exchange提供了修改请求头信息的方法mutateServerWebExchange build = exchange.mutate().request(b -> b.header("user-info",userinfo)).build();System.out.println("userId = " + userId);return chain.filter(build);}private boolean isPath(RequestPath path) {//转为String类型String string = path.toString();//将配置文件中定义的路径进行遍历for (String excludePath : authProperties.getExcludePaths()) {if (antPathMatcher.match(excludePath, string)){//使用工具类进行匹配 antPathMatcher.match ,匹配成功返回truereturn true;}}return false;}@Overridepublic int getOrder() {return 0;}
}

定义拦截器:
拦截器实现了HandlerInterceptor接口
package com.hmall.common.interceptor;import cn.hutool.core.util.StrUtil;
import com.hmall.common.utils.UserContext;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;// 拦截器需要进行注册
public class UserINfointerceptor implements HandlerInterceptor {//请求到达时执行获取用户信息@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取请求头中的用户信息String userInfo = request.getHeader("user-info");// 2.判断是否为空if (StrUtil.isNotBlank(userInfo)) {// 不为空,保存到ThreadLocalUserContext.setUser(Long.valueOf(userInfo));System.out.println(userInfo);}// 3.放行return true;}//业务执行后的操作,删除线程存储中的数据@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {UserContext.removeUser();}
}
由于拦截器需要配置类进行注册才可以启用,创建一个配置类:
由于网关模块并没有使用springMVC进行编写,所以网关就会报错,因此使用该注解:@ConditionalOnClass(DispatcherServlet.class)//用于判断是否存在某个类,存在就加载,不存在就不加载,使得网关模块不在加载该配置类,避免报错。
package com.hmall.common.config;import com.hmall.common.interceptor.UserINfointerceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration//配置类的指定注释
@ConditionalOnClass(DispatcherServlet.class)//用于判断是否存在某个类,存在就加载,不存在就不加载
public class MyUserInfoConfig implements WebMvcConfigurer {//将拦截器添加到容器中@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserINfointerceptor ());}
}
在hm-common模块下的文件 spring.factories 中添加路径,在启动时扫描该配置
添加该代码:
com.hmall.common.config.MyUserInfoConfig,\
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.hmall.common.config.MyBatisConfig,\com.hmall.common.config.MyUserInfoConfig,\com.hmall.common.config.JsonConfig
OpenFeign传递用户

在Api模块中的
DefaultFeignConfig配置类中添加拦截器,拦截所有的okhttp请求即所有的微服务之间的请求
使用匿名内部类进行配置
由于需要获取用户信息,添加hm-common的依赖获取UserContext对象。
<!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency>
@Beanpublic RequestInterceptor MyRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {Long user = UserContext.getUser();if (user != null){requestTemplate.header("user-info",user.toString());}}};}
package com.hmall.api.config;import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor MyRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {Long user = UserContext.getUser();if (user != null){requestTemplate.header("user-info",user.toString());}}};}
}
微服务的登录解决方案:

配置管理


配置共享
我们可以把微服务共享的配置抽取到Nacos中统一管理,这样就不需要每个微服务都重复配置了。分为两步:
-
在Nacos中添加共享配置
-
微服务拉取配置
添加共享配置:
1、在nacos的配置列表下进行新建共享配置
- Data ID:表示共享配置文件的名称,即在项目中引入是的名字
- 使用默认分组
- 配置内容即要共享的配置,可以使用占位符进行动态的设置配置数据

jdbc的更共享配置:shared-jdbc.yaml ,有数据库设置和mp的配置使用占位符来进行不同的设置。
占位符后面的 :表示默认字符,即没有设置的默认数据
spring:datasource:url: jdbc:mysql://${hm.db.host:192.168.21.101}:${hm.db.port:3306}/${hm.db.database}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: ${hm.db.user:root}password: ${hm.db.pw:123}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto
日志的共享配置: shared-log.yaml
logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: "logs/${spring.application.name}"
swagger的共享配置;shared-swagger.yaml
knife4j:enable: trueopenapi:title: ${hm.swagger.title:黑马商城接口文档}description: ${hm.swagger.description:黑马商城接口文档}email: ${hm.swagger.email:zhanghuyi@itcast.cn}concat: ${hm.swagger.concat:虎哥}url: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- ${hm.swagger.package}
接下来,我们要在微服务拉取共享配置。将拉取到的共享配置与本地的application.yaml配置合并,完成项目上下文的初始化。
不过,需要注意的是,读取Nacos配置是SpringCloud上下文(ApplicationContext)初始化时处理的,发生在项目的引导阶段。然后才会初始化SpringBoot上下文,去读取application.yaml。
也就是说引导阶段,application.yaml文件尚未读取,根本不知道nacos 地址,该如何去加载nacos中的配置文件呢?
SpringCloud在初始化上下文的时候会先读取一个名为bootstrap.yaml(或者bootstrap.properties)的文件,如果我们将nacos地址配置到bootstrap.yaml中,那么在项目引导阶段就可以读取nacos中的配置了。

/2、在项目中引入依赖:
<!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>
创建bootstrap.yml
spring:application:name: cart-service # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.21.101 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-jdbc.yaml # 共享mybatis配置- dataId: shared-log.yaml # 共享日志配置- dataId: shared-swagger.yaml # 共享日志配置
修改原有的配置文件,为占位符赋值 application.yaml
server:port: 8082
feign:okhttp:enabled: true # 开启OKHttp连接池支持
hm:swagger:title: 购物车服务接口文档package: com.hmall.cart.controllerdb:database: hm-cart
配置热更新

注意文件的dataId格式:
[服务名]-[spring.active.profile].[后缀名]
文件名称由三部分组成:
-
服务名:我们是购物车服务,所以是cart-service -
spring.active.profile:就是spring boot中的spring.active.profile,可以省略,则所有profile共享该配置 -
后缀名:例如yaml
设置nacos配置热更新文件:
名字为:cart-service
hm:cart:maxAmount: 10
在代码中创建配置类:,设置配置文件关联。
创建包: config
@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {private Integer maxAmount;
}
修改业务文件中判断购物车最大数量:
private void checkCartsFull(Long userId) {int count = Math.toIntExact(lambdaQuery().eq(Cart::getUserId, userId).count());if (count >= cartProperties.getMaxAmount()) {throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", cartProperties.getMaxAmount()));}}
动态路由
动态路由的相关操作
相关文章:
微服务day04
网关 网关路由 快速入门 创建新模块:hm-gateway继承hmall父项目。 引入依赖:引入网关依赖和nacos负载均衡的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"…...
Spring Boot 集成JWT实现Token验证详解
文章目录 Spring Boot 集成JWT实现Token验证详解一、引言二、JWT和Token基础1、什么是Token2、什么是JWT3、JWT的结构4、JWT的工作原理 三、集成JWT1、引入JWT依赖2、创建Token工具类3、创建拦截器4、注册拦截器 四、总结 Spring Boot 集成JWT实现Token验证详解 一、引言 在现…...
如何快速搭建一个spring boot项目
一、准备工作 1.1 安装JDK:确保计算机上已安装Java Development Kit (JDK) 8或更高版本、并配置了环境变量 1.2 安装Maven:下载并安装Maven构建工具,这是Spring Boot官方推荐的构建工具。 1.3 安装代码编辑器:这里推荐使用Inte…...
学习笔记:黑马程序员JavaWeb开发教程(2024.11.9)
9.1 Mybatis-基础操作-环境准备 这里也没做,到时候写案例,如果需要环境配置什么的,可以看看这个 9.2 Mybatis-基础操作-删除 删除需要动态获取需要删除的id,使用方法传参,#{}的方式实现 在编写的delete方法中&a…...
【软考】系统分析师第二版 新增章节 第20章微服务系统分析与设计
微服务系统是一类基于微服务架构风格的分布式系统,它将应用程序拆分成多个独立的小型服务,每个服务都运行在独立的进程中,并采用轻量级通信协议进行通信。这些服务可以由不同的团队开发、不同的编程语言编写,并且可以按需部署。微…...
抓包工具WireShark使用记录
目录 网卡选择: 抓包流程: 捕获过滤器 常用捕获过滤器: 抓包数据的显示 显示过滤器: 常用的显示过滤器: 实际工作中,在平台对接,设备对接等常常需要调试接口,PostMan虽然可以进…...
C++上机实验|多态性编程练习
1.实验目的 (1)理解多态性的概念。 (2)掌握如何用虚函数实现动态联编 (3)掌握如何利用虚基类。 2.实验内容 设计一个飞机类 plane,由它派生出歼击机类fighter和轰炸机类 bomber,歼击机类fighter 和轰炸机类bomber 又共同派生出歼轰机(多用途战斗机)。利用虚函数和虚基类描述…...
php伪协议介绍
PHP伪协议共有12种,具体如下: file:// — 访问本地文件系统http:// — 访问 HTTP(s) 网址ftp:// — 访问 FTP(s) URLsphp:// — 访问各个输入/输出流(I/O streams)php://stdin, php://stdout 和 php://stderrphp://inputphp://outputphp://memory 和 php://tempphp://filte…...
『事善能』MySQL基础 — 2.MySQL 5.7安装(一)
1、通过msi安装软件进行MySQL安装 (1)点击运行MySQL安装文件 (2)选择安装类型 我们选择自定义安装,点击Next。 说明 Develop Default:默认开发类型,安装MySQL服务器以及开发MySQL应用所需要的工…...
漫谈分布式唯一ID
文章目录 本系列前言UUIDDB自增主键Redis incr命令号段模式雪花算法 本系列 漫谈分布式唯一ID(本文)分布式唯一ID生成(二):leaf分布式唯一ID生成(三):uid-generator(待完…...
【复旦微FM33 MCU 开发指南】ADC
前言 本系列基于复旦微FM33LC0系列单片机的DataSheet编写,旨在提供手册解析和开发指南。 本文章及本系列其他文章将持续更新,本系列其它文章请跳转【复旦微FM33 MCU 外设开发指南】总集篇 本文章最后更新日期:2024/11/09 全文字数ÿ…...
ORB_SLAM3安装
ORB_SLAM3安装 一.前期准备1.1ubuntu查看当前版本的命令1.2 根据ubuntu版本,更新下载软件源1.3 先下载git1.4 vim语法高亮1.5 常见的linux命令 二.ORB-SLAM3下载2.1 ORB_SLAM3源码下载2.2 安装依赖库2.2.1 依赖库2.2.2 安装pangolin2.2.3 安装opencv2.2.4 Eigen3安装…...
GoLang协程Goroutiney原理与GMP模型详解
本文原文地址:GoLang协程Goroutiney原理与GMP模型详解 什么是goroutine Goroutine是Go语言中的一种轻量级线程,也成为协程,由Go运行时管理。它是Go语言并发编程的核心概念之一。Goroutine的设计使得在Go中实现并发编程变得非常简单和高效。 以下是一些…...
全文检索ElasticSearch到底是什么?
学习ElasticSearch之前,我们先来了解一下搜索 1 搜索是什么 ① 概念:用户输入想要的关键词,返回含有该关键词的所有信息。 ② 场景: 1互联网搜索:谷歌、百度、各种新闻首页; 2 站内搜索ÿ…...
FPGA实现串口升级及MultiBoot(五)通过约束脚本添加IPROG实例
本文目录索引 一个指令和三种方式通过约束脚本添加Golden位流工程MultiBoot位流工程验证example1总结代码缩略词索引: K7:Kintex 7V7:Vertex 7A7:Artix 7MB:MicroBlaze上一篇文章种总结了MultiBoot 关键技术,分为:一个指令、二种位流、三种方式、四样错误。针对以上四句话我…...
文献阅读 | Nature Methods:使用 STAMP 对空间转录组进行可解释的空间感知降维
文献介绍 文献题目: 使用 STAMP 对空间转录组进行可解释的空间感知降维 研究团队: 陈金妙(新加坡科学技术研究局) 发表时间: 2024-10-15 发表期刊: Nature Methods 影响因子: 36.1࿰…...
【模块化大作战】Webpack如何搞定CommonJS与ES6混战(1-3)
在前端开发中,模块化是一个重要的概念,不同的模块化标准有不同的特点和适用场景。webpack 同时支持 CommonJS 和 ES6 Module,因此需要理解它们在互操作时 webpack 是如何处理的。 同模块化标准 如果导出和导入使用的是同一种模块化标准&…...
[NewStar 2024] week5完结
每次都需要用手机验证码登录,题作的差不多就没再进过。今天把week5解出的部分记录下。好像时间过去很久了。 Crypto 没e也能完 这题给了e,p,q,dp,dq。真不清楚还缺啥 long_to_bytes(pow(c,dp,p)) 格格你好棒 给了a,b和提示((p2*r) * 3*a q) % b < 70 其中r…...
IntelliJ IDEA的快捷键
IntelliJ IDEA 是一个非常强大的集成开发环境,它提供了大量的快捷键来加速开发者的日常工作。这里为您整理了一份 IntelliJ IDEA 的快捷键大全,包含了编辑、导航、重构、运行等多个方面的快捷键。请注意,这些快捷键是基于 Windows 版本的 Int…...
暮雨直播 1.3.2 | 内置直播源,频道丰富,永久免费
暮雨直播是一款内置直播源的电视直播应用程序,提供丰富的频道内容,包括教学、首页、一线、博主、解说、动漫、堆堆等。该应用的内置直播源持续更新维护,确保用户可以稳定地观看各种电视频道。暮雨直播承诺永久免费,为用户提供了一…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
