当前位置: 首页 > news >正文

统⼀服务入口 - Gateway

网关介绍

问题

        在 spring cloud 体系中我们通过 Eureka,Nacos 解决了服务注册,服务发现的问题,使⽤Spring Cloud LoadBalance解决了负载均衡的问题,使⽤ OpenFeign 解决了远程调⽤的问题.

        但是当前所有微服务的接⼝都是直接对外暴露的,可以直接通过外部访问.为了保证对外服务的安全性,服务端实现的微服务接⼝通常都带有⼀定的权限校验机制.由于使⽤了微服务,原本⼀个应⽤的的多个模块拆分成了多个应⽤,我们不得不实现多次校验逻辑.当这套逻辑需要修改时,我们需要修改多个应⽤,加重了开发⼈员的负担.针对以上问题,常⽤的解决⽅案是使⽤API⽹关.

什么是 API 网关

        API网关(简称网关)也是⼀个服务,通常是后端服务的唯⼀⼊⼝.它的定义类似设计模式中的Facade 模式 (⻔⾯模式,也称外观模式).它就类似整个微服务架构的⻔⾯,所有的外部客户端访问,都需要经过它来进⾏调度和过滤.

        简单理解:我们在进行微服务开发时,每个微服务都提供了接口,但这些接口是用于进行业务处理的,不应该被暴露在外界,如果我们为每个微服务都设置权限管理,这是十分麻烦的。所以就需要  API 网关作为整个微服务架构的⻔⾯,所有的请求都要先交给 API 网关, API 网关校验后再通过服务注册中心将请求转发给对应的服务接口,由于 API 网关已经校验了,后续的微服务就不需要在校验请求了。

网关核⼼功能:

        权限控制:作为微服务的⼊⼝,对⽤户进⾏权限校验,如果校验失败则进⾏拦截

        动态路由:⼀切请求先经过⽹关,但⽹关不处理业务,⽽是根据某种规则,把请求转发到某个微服务

        负载均衡:当路由的⽬标服务有多个时,还需要做负载均衡,限流:请求流量过⾼时,按照⽹关中配置微服务能够接受的流量进⾏放⾏,避免服务压⼒过⼤.

Spring Cloud Gateway

快速上手

我们通过以下的演⽰,先来了解⽹关的基本功能

创建网关项目

        API ⽹关也是⼀个服务

引⼊⽹关依赖

        由于 API ⽹关在接收并检验用户请求后要将请求转发给对应的服务,所以  API ⽹关也需要注册到 nacos 上,所以引入 nacos 的依赖, API ⽹关应当均衡的向服务转发请求,需要用到负载均衡,所以引入负载均衡工具 loadbalancer 的依赖

<!--⽹关-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--基于nacos实现服务发现依赖-->
<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>

编写启动类

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

添加 Gateway 的路由配置

创建 application.yml ⽂件,添加如下配置:

        凡是需要接收外界请求的服务都需要在网关这里配置路由,这样网关才能将请求发给对应的服务

server:port: 10030 # ⽹关端⼝
spring:application:name: gateway # 服务名称cloud:nacos:discovery:server-addr: 127.0.0.1:8848gateway:routes: # ⽹关路由配置- id: product-service #路由ID, ⾃定义, 唯⼀即可uri: lb://product-service #⽬标服务地址predicates: #路由条件- Path=/product/**- id: order-serviceuri: lb://order-servicepredicates:- Path=/order/**

        配置字段说明:

        • id :⾃定义路由ID,保持唯⼀(推荐将其写为目标服务的名称)

        • uri:⽬标服务地址,⽀持普通 URI及 lb:// 应⽤注册服务名称 .lb表⽰负载均衡,使⽤ lb:// ⽅ 式表⽰从注册中⼼获取服务地址.

        • predicates: 路由条件,根据匹配结果决定是否执⾏该请求路由,上述代码中,我们把符合 Path 规则的⼀切请求,都代理到 uri 参数指定的地址.

        当我们要为一个服务设置多个条件时,可以用 ,隔开

predicates:- Path=/order/**,/feign/**

        配置好以后我们就可以通过⽹关服务访问 product-service 和 order-service 了,10030 是网关的端口

        http://127.0.0.1:10030/product/1

        http://127.0.0.1:10030/order/1

Route Predicate Factories

Predicate

        Predicate 是Java 8 提供的⼀个函数式编程接⼝,它接收⼀个参数并返回⼀个布尔值,⽤于条件过滤,请求参数的校验.

@FunctionalInterface
public interface Predicate<T> {boolean test(T t);//...
}

代码演⽰:

1. 定义⼀个 Predicate

class StringPredicate implements Predicate<String>{@Overridepublic boolean test(String str) {return str.isEmpty();}
}

2. 使⽤这个 Predicate

public class PredictTest {public static void main(String[] args) {Predicate<String> predicate = new StringPredicate();System.out.println(predicate.test(""));System.out.println(predicate.test("bite666"));}
}

3. 运⾏结果

4. Predicate 的其他写法

1)内置函数

public class PredictTest {public static void main(String[] args) {Predicate<String> predicate = new Predicate<String>(){@Overridepublic boolean test(String s) {return s.isEmpty();}};System.out.println(predicate.test(""));System.out.println(predicate.test("bite666"));}
}

2)lambda写法

public class PredictTest {public static void main(String[] args) {Predicate<String> predicate = s -> s.isEmpty();System.out.println(predicate.test(""));System.out.println(predicate.test("bite666"));}
}

5. Predicate 的其他⽅法

• isEqual(Object targetRef):⽐较两个对象是否相等,参数可以为Null

• and(Predicate other): 短路与操作,返回⼀个组成 Predicate

• or(Predicate other):短路或操作,返回⼀个组成 Predicate

• test(T t):传⼊⼀个 Predicate 参数,⽤来做判断

• negate():返回表⽰此 Predicate 逻辑否定的 Predicate

Route Predicate Factories(路由断言工厂)

        Route Predicate Factories(路由断⾔⼯⼚,也称为路由谓词⼯⼚,此处谓词表⽰⼀个函数),在Spring Cloud Gateway中, Predicate 提供了路由规则的匹配机制.我们在配置⽂件中写的断⾔规则只是字符串,这些字符串会被 Route Predicate Factory读取并处理,转变为路由判断的条件.

        ⽐如前⾯章节配置的 Path=/product/** ,就是通过 Path 属性来匹配 URL 前缀是 /product 的请求.这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateF actory 来实现的. Spring Cloud Gateway 默认提供了很多 Route Predicate Factory,这些 Predicate会分别匹配 HTTP 请求的不同属性,并且多个 Predicate 可以通过 and 逻辑进⾏组合.

        

        

更多请参考:Route Predicate Factories :: Spring Cloud Gateway

代码演⽰:

在application.yml 中添加如下规则:

spring:cloud:gateway:routes: # ⽹关路由配置 - id: product-service #路由ID, ⾃定义, 唯⼀即可 uri: lb://product-service #⽬标服务地址 predicates: #路由条件 - Path=/product/**- After=2025-01-01T00:00:00.000+08:00[Asia/Shanghai]

增加限制路由规则:请求时间为 2025年1⽉1⽇之后

Gateway Filter Factories(⽹关过滤器⼯⼚)

        Predicate 决定了请求由哪⼀个路由处理,如果在请求处理前后需要加⼀些逻辑,这就是 Filter(过滤器)的 作⽤范围了.

        Filter分为两种类型: Pre 类型和 Post 类型. 

        Pre 类型过滤器:路由处理之前执⾏(请求转发到后端服务之前执⾏),在 Pre 类型过滤器中可以做鉴权, 限流等.

        Post 类型过滤器:请求执⾏完成后,将结果返回给客户端之前执⾏

        过滤器可有可⽆.

        Spring Cloud Gateway 中内置了很多Filter,⽤于拦截和链式处理 web 请求.⽐如权限校验,访问超时等设定. Spring Cloud Gateway 从作⽤范围上,把 Filter 可分为 GatewayFilterGlobalFilter.

        GatewayFilter: 应⽤到单个路由或者⼀个分组的路由上 GlobalFilter: 应⽤到所有的路由上,也就是对所有的请求⽣效.

GatewayFilter(过滤器)

        GatewayFilter 同 Predicate 类似,都是在配置⽂件 application.yml 中配置,每个过滤器的逻辑都是固定的.⽐如 AddRequestParameterGatewayFilterFactory 只需要在配置⽂件中写 AddRequestParameter ,就可以为所有的请求添加⼀个参数,我们先通过⼀个例⼦来演⽰ GatewayFilter 如何使⽤.

快速上手

1. 在 application.yml 中添加 filter

server:port: 10030 # ⽹关端⼝ 
spring:application:name: gateway # 服务名称 cloud:nacos:discovery:server-addr: 110.41.51.65:10020gateway:routes: # ⽹关路由配置 - id: product-service #路由ID, ⾃定义, 唯⼀即可 uri: lb://product-service #⽬标服务地址 predicates: #路由条件 - Path=/product/**- After=2024-01-01T00:00:00.000+08:00[Asia/Shanghai]filters:- AddRequestParameter=userName, yulin- id: order-serviceuri: lb://order-servicepredicates:- Path=/order/**

        该 filter 只添加在了 product-service 路由下,因此只对 product-service 路由⽣效, 也就是 对 /product/** 的请求⽣效.

        该 filter 表示,将请求发送给服务之前,向服务中添加一个 userName 参数,值为 yulin

filters:- AddRequestParameter=userName, yulin

        GatewayFilter说明: Spring Cloud Gateway提供了的 Filter ⾮常多,下⾯列出⼀些常⻅过滤器的说明.

详细可参考官⽅⽂档:GatewayFilter Factories :: Spring Cloud Gateway

Default Filters

        前⾯的 filter 添加在指定路由下,所以只对当前路由⽣效,若需要对全部路由⽣效,可以使⽤ spring.cloud.gateway.default-filters 这个属性需要⼀个 filter 的列表.

配置举例:

spring:cloud:gateway:default-filters:- AddResponseHeader=X-Response-Default-Red, Default-Blue- PrefixPath=/httpbin

GlobalFilter(全局过滤器)

        GlobalFilter 是 Spring Cloud Gateway中的全局过滤器,它和 GatewayFilter 的作⽤是相同的. GlobalFilter 会应⽤到所有的路由请求上,全局过滤器通常⽤于实现与安全性,性能监控和⽇志记录等相关的全局功能.Spring Cloud Gateway 内置的全局过滤器也有很多,⽐如:

 • Gateway Metrics Filter: ⽹关指标, 提供监控指标

• Forward Routing Filter: ⽤于本地 forword, 请求不转发到下游服务器

• LoadBalancer Client Filter: 针对下游服务,实现负载均衡.

• ...更多过滤器参考:Global Filters :: Spring Cloud Gateway

快速上手

1. 添加依赖

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

2. 添加配置

spring:cloud:gateway:metrics:enabled: true
management:endpoints:web:exposure:include: "*"endpoint:health:show-details: alwaysshutdown:enabled: true

3. 测试 http://127.0.0.1:10030/actuator,显⽰所有监控的信息链接

过滤器执⾏顺序

        ⼀个项⽬中,既有 GatewayFilter,⼜有 GlobalFilter 时,执⾏的先后顺序是什么呢?请求路由后,⽹关会把当前项⽬中的 GatewayFilter 和 GlobalFilter 合并到⼀个过滤器链(集合)中,并进⾏排序,依次执⾏过滤器.

        每⼀个过滤器都必须指定⼀个 int 类型的 order 值,默认值为0,表⽰该过滤的优先级.order 值越⼩,优先级越⾼,执⾏顺序越靠前.

        • Filter 通过实现 Order 接⼝或者添加 @Order 注解来指定 order 值.

        • Spring Cloud Gateway 提供的 Filter 由 Spring 指定.⽤户也可以⾃定义 Filter,由⽤户指定.

        • 当过滤器的 order 值⼀样时,会按照 defaultFilter > GatewayFilter > GlobalFilter 的顺序执⾏.

自定义过滤器

        Spring Cloud Gateway提供了过滤器的扩展功能,开发者可以根据实际业务来⾃定义过滤器,同样⾃定义过滤器也⽀持 GatewayFilter 和 GlobalFilter 两种

自定义 GatewayFilter

        自定义 GatewayFilter,需要去实现对应的接⼝ GatewayFilterFactory ,Spring Boot 默认帮我们实现的抽象类是 AbstractGatewayFilterFactory ,我们可以直接使⽤

定义GatewayFilter

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Slf4j
@Service
public class CustomGatewayFilterFactory extendsAbstractGatewayFilterFactory<CustomGatewayFilterFactory.CustomConfig>implements Ordered {public CustomGatewayFilterFactory() {super(CustomConfig.class);}@Overridepublic GatewayFilter apply(CustomConfig config) {/*** Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)* ServerWebExchange: HTTP请求-响应交互的契约, 提供对HTTP请求和响应的访问, 服务器端请求属性, 请求实例,响应实例等, 类似Context⻆⾊ * GatewayFilterChain: 过滤器链 * Mono: Reactor核⼼类, 数据流发布者, Mono最多只触发⼀个事件, 所以可以把 Mono ⽤于在异步任务完成时发出通知. * Mono.fromRunnable: 创建⼀个包含Runnable元素的数据流 */return ((exchange, chain) -> {//在请求前的操作log.info("[Pre] Filter Request, name:"+config.getName());//在请求后的操作return chain.filter(exchange).then(Mono.fromRunnable(()->{log.info("[Post] Response Filter");}));});}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE; //配置优先级, order越⼤, 优先级越低 }
}

针对这个 Filter 的配置,使⽤ CustomConfig 定义

@Data
public static class CustomConfig {private String name;
}

代码说明:

        1. 类名统⼀以 GatewayFilterFactory 结尾,因为默认情况下,过滤器的 name 会采⽤该定义类的前缀.这⾥的 name=Custom (yml配置中使⽤)

        2. apply⽅法中,同时包含 Pre 和 Post 过滤,then⽅法中是请求执⾏结束之后处理的

        3. CustomConfig 是⼀个配置类,该类只有⼀个属性 name,和 yml 的配置对应

        4. 该类需要交给 Spring 管理,所以需要加 @Service 注解

        5. getOrder表⽰该过滤器的优先级,值越⼤,优先级越低.

配置过滤器

spring:cloud:gateway:routes: # ⽹关路由配置 - id: product-service #路由ID, ⾃定义, 唯⼀即可 uri: lb://product-service #⽬标服务地址 predicates: #路由条件 - Path=/product/**filters:- name: Customargs:name: custom filter
⾃定义 GlobalFilter

        GlobalFilter 的实现⽐较简单,它不需要额外的配置,只需要实现 GlobalFilter 接⼝,⾃动会过滤所有的 Filter.

定义GlobalFilter

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Slf4j
@Service
public class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChainchain) {//请求前执行的操作log.info("[Pre] CustomGlobalFilter enter...");//请求后执行的操作return chain.filter(exchange).then(Mono.fromRunnable(()->{log.info("[Post] CustomGlobalFilter return...");}));}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE;//配置优先级, order越⼤, 优先级越低 }
}

相关文章:

统⼀服务入口 - Gateway

网关介绍 问题 在 spring cloud 体系中我们通过 Eureka,Nacos 解决了服务注册,服务发现的问题,使⽤Spring Cloud LoadBalance解决了负载均衡的问题,使⽤ OpenFeign 解决了远程调⽤的问题. 但是当前所有微服务的接⼝都是直接对外暴露的,可以直接通过外部访问.为了保证对外服务的…...

QGraphicsWidget Class

Header:#include < QGraphicsWidget > qmake:QT += widgets Since:Qt 4.4 Inherits:QGraphicsObject and QGraphicsLayoutItem Inherited By:QGraphicsProxyWidget This class was introduced in Qt 4.4. Public Types enum anonymous {Type }Properties autoFi…...

探讨最好用的AI工具:从日常到创新的应用

文章目录 引言常用AI工具1. 语音助手2. 图像识别软件3. 机器翻译工具4. 智能客服系统 创新AI应用1. 自动驾驶汽车2. 虚拟试衣间3. 医疗影像分析4. 个性化推荐系统 个人体验分享1. 通义灵码2. 文心一言3. 智能写作助手4. 智能家居设备5. DALLE6. Whisper7. Codex8. Gym9. ChatGP…...

Python系统教程005(字符串的格式化输出)

知识回顾 1、默认情况下&#xff0c;input函数接收的数据是字符串类型。 2、字符串类型的关键词是str。 3、\n和\t都是转义字符&#xff0c;\n用来换行&#xff0c;\t用来留出一段固定长度的空白。 4、type函数能够用来查看变量的数据类型 5、数据类型的转换&#xff0c;举…...

六款电脑远程控制软件分享,2024最热门软件合集,总有一款适合你!速来看!

想要随时随地控制自己的电脑&#xff1f; 无论你是办公需求&#xff0c;还是要远程协助他人&#xff0c;一款好用的远程控制软件绝对少不了。 2024年最热门的六款远程控制软件已经为你准备好&#xff0c;总有一款适合你&#xff0c;赶快往下看吧&#xff01; 1. 安企神系统—…...

优质微信群不再难寻!掌握这些技巧就够了!

在当今信息爆炸的时代&#xff0c;微信群已成为人们交流思想、分享知识、建立人脉的重要平台。无论是专业领域的深入探讨&#xff0c;还是兴趣爱好的自由交流&#xff0c;微信群都能为你提供一个即时互动的虚拟空间。然而&#xff0c;面对海量的微信群信息&#xff0c;如何高效…...

python - mysql操作

Python MySQL 操作 1. 背景介绍 常见的Mysql驱动介绍&#xff1a; MySQL-python&#xff1a;也就是MySQLdb。是对C语言操作MySQL数据库的一个简单封装。遵循了Python DB API v2。但是只支持Python2&#xff0c;目前还不支持Python3。mysqlclient&#xff1a;是MySQL-python的…...

基于Springboot+Vue的服装生产管理信息系统设计与实现(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 在这个…...

75.【C语言】文件操作(2)

承接74.【C语言】文件操作(1)文章 目录 5.详细阐释文件的打开和关闭 1.流 2.标准流 3.文件指针 FILE 两层含义 附:FILE的头文件 4.操作文件的步骤 1.fopen函数 ​编辑 简写的全称查询 输入&输出的含义 2.fclose函数 3.代码示例 补充:绝对路径和相对路径 注意…...

Redis 使用记录

封装调用redis类 import redis from conf.config import RedisConfigclass RedisConfig:redis_json config_data[redis_config]redis_pwd env.get(project_name).get(pwd)host redis_json.get("host")dialog_states_db redis_json.get("dialog_states_db&q…...

IDEA实用小技巧

1. IDEA代码提示忽略大小写 打开设置&#xff0c;点击Editor–>General–>Code Completion &#xff0c;然后将右侧的Match Case前面的选框去掉勾选。 2. 快速查找接口RestfulToolkitX插件 该插件可以快速查找接口&#xff08;快捷键为CTRL\&#xff09; 还会在侧边栏…...

PEI转染试剂对血清的敏感性研究

在细胞生物学和基因工程领域&#xff0c;聚乙烯亚胺&#xff08;PEI&#xff09;作为一种常用的转染试剂&#xff0c;广泛应用于基因的递送。然而&#xff0c;PEI转染试剂对血清的敏感性一直是研究的热点问题。转染过程中&#xff0c;血清作为培养基的成分之一&#xff0c;可能…...

手机怎样改网络ip地址?内容详尽实用

随着网络技术的发展&#xff0c;更改手机IP地址已成为一种常见需求。本文将详细介绍如何在不同网络环境下更改手机IP地址&#xff0c;包括移动网络和WiFi网络&#xff0c;以及同时适用于两种网络的方法&#xff0c;内容详尽实用&#xff0c;干货满满。 一、适用于移动网络&…...

使用Pybind11,Python调用C++动态库

最近学习了一下pybind11&#xff0c;使用python来调用C动态库的模式&#xff0c;在某些场景下有用&#xff0c;这里做一个记录。 环境准备 安装python&#xff0c;我这里安装的是3.12版本 下载Pybind11库&#xff0c;这是一个仅包含头文件的轻量级库&#xff0c;使用起来非常…...

提交gitlab

1.gitlab上新建项目 2.git clone url把新项目拉下来 3.git add ./* 把需要提交的文件全部新增 4.git config --global user.email “yetuo.zhuqxsk.local” 身份认证一下 5.git commit -m “asr语音识别-对外服务” 提交 6.git push origin 推送进去 git init git add . git c…...

金慧-综合管理信息系统 LoginBegin.aspx SQL注入复现

0x01 产品描述&#xff1a; 金慧-综合管理信息系统&#xff08;以下简称“金慧综合管理系统”&#xff09;是上海金慧软件有限公司基于多年行业系统研发和实施经验&#xff0c;为各类企业量身定制的一套综合性管理解决方案。该系统旨在通过信息化手段&#xff0c;提升企业的管理…...

RHCSA的学习(4)

一、vi编辑器 &#xff08;1&#xff09;为什么学vi&#xff1f; 所有的Unix Like 系统都会内建 vi 文本编辑器&#xff0c;其他的文本编辑器则不一定会存在&#xff1b; 很多个别软件的编辑接口都会主动呼叫 vi (例如未来会谈到的 crontab, visudo, edquota 等指令)&#x…...

linux-二进制工具

二进制查看工具: 1、hexdump -n length 只格式化输入文件的前length个字节 -C 输出规范的十六进之和ASCII码 -b 单字节八进制显示 -c 单字节字符显示 -d 双字节十进制显示 -o 双字节八进制显示 -x 双字节十六进制显示 -s 从偏移量开始输出 2、od(octal dump) 用于显示文件内…...

《数据结构》学习系列

系列文章目录 一、绪论 二、线性表、链表 三、堆栈、队列 四、数组 五、字符串 六、树...

沂机管理系统/data/Ajax.aspx接口存在SQL注入漏洞

漏洞描述 沂机管理系统/data/Ajax.aspx接口存在SQL注入漏洞&#xff0c;攻击者可以获取服务器权限 漏洞复现 body"后台管理系统演示版" POC GET /data/Ajax.aspx?methodlog_list&page1&limit20&fkey1&fdate12024-10-0100%3A00%3A00&fdate2…...

JVM 内存模型与垃圾回收过程详解

JVM 内存模型与垃圾回收过程详解 文章目录 JVM 内存模型与垃圾回收过程详解1. JVM内存分区1.1 具体分区1.2 JVM内存分区的必要性 2. 垃圾回收2.1 CMS垃圾回收器2.2 G1垃圾回收器2.3 JVM垃圾回收从新生代到老年代 1. JVM内存分区 1.1 具体分区 Java虚拟机&#xff08;JVM&#…...

python:PyPDF2 将多个图片转换为pdf,再合并成一个PDF文件

承上一篇&#xff1a;java&#xff1a;pdfbox 3.0 去除扫描版PDF中文本水印 # 导出扫描版PDF文件中每页的图片文件 java -jar pdfbox-app-3.0.3.jar export:images -prefixtest -i your_book.pdf 导出 Writing image: test-1.jpg Writing image: test-2.jpg Writing image: t…...

Python精选200Tips:186-190

针对序列&#xff08;时间、文本&#xff09;数据的网络结构 续 P186-- 双向LSTM(Bidirectional Long Short-Term Memory 2005)&#xff08;1&#xff09;模型结构说明&#xff08;2&#xff09;创新性说明&#xff08;3&#xff09;示例代码&#xff1a;IMDB电影评论情感分析 …...

C、C++常用数据结构:链表

文章目录 基本概念链表的创建链表结点定义链表创建 链表遍历链表释放链表查找链表删除链表插入测试用例 基本概念 参考&#xff1a;链表基础知识详解&#xff08;非常详细简单易懂&#xff09;-CSDN博客 链表是一种线性存储结构&#xff0c;链表在物理存储上是非连续的&#xf…...

【devops】devops-ansible之剧本变量使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8》从问题中去学习k8s 《docker学习》暂未更…...

《Linux从小白到高手》理论篇:一文概览常用Linux重要配置文件

List item 今天继续宅家&#xff0c;闲来无事接着写。本篇是《Linux从小白到高手》理论篇的最后一篇了。本篇集中介绍所有常用的Linux重要配置文件。 用这个命令可以查看配置文件所在的位置&#xff1a;如上图 locate "*.conf" "*.ini" "*.cfg&quo…...

采购管理流程:掌握最后阶段的关键要点

采购管理流程是企业运作中的核心职能之一&#xff0c;涵盖了获取商品和服务的一系列步骤&#xff0c;旨在以高效率和经济效益的方式进行。深入理解该流程的每个环节极为关键&#xff0c;特别是最后阶段&#xff0c;这可确保所有采购活动的圆满完成以及与供应商维持良好关系。 …...

cherry-markdown开源markdown组件详细使用教程

文章目录 前言开发定位目标调研技术方案前提工作量安排数据库表设计实现步骤1、引入依赖2、实现cherry-markdown的vue组件&#xff08;修改上传接口路径&#xff09;3、支持draw.io组件4、支持展示悬浮目录toc前端使用&#xff1a;编辑状态使用cherry-markdown的vue组件前端使用…...

Android SystemUI组件(10)禁用/重启锁屏流程分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分 应用入口处理流程解读 即可。 在 Android 系统中&#xff0c;禁用锁屏…...

【Geeksend邮件营销】外贸邮件中的一些常用语

外贸邮件中的相关术语丰富多样&#xff0c;涉及邮件的开头、正文、结尾以及特定的商务用语。以下是一些常用的外贸邮件术语及其解释&#xff1a; 一、邮件开头用语 1、问候语&#xff1a; Dear [收件人姓名]&#xff0c; Trust this email finds you well. How are you? …...