基于 SpringBoot 2.7.x 使用最新的 Elasticsearch Java API Client 之 ElasticsearchClient
1. 从 RestHighLevelClient 到 ElasticsearchClient
从 Java Rest Client 7.15.0 版本开始,Elasticsearch 官方决定将 RestHighLevelClient 标记为废弃的,并推荐使用新的 Java API Client,即 ElasticsearchClient. 为什么要将 RestHighLevelClient 废弃,大概有以下几点:
- 维护成本高:RestHighLevelClient 需要和 Elasticsearch APIs 的更新保持一致,而 Elasticsearch APIs 更新较为频繁,因此每次 Elasticsearch APIs 有新的迭代,RestHighLevelClient 也要跟着迭代,维护成本高。
- 兼容性差: 由于 RestHighLevelClient 和 Elasticsearch 的内部数据结构紧耦合,而 Elasticsearch 不同版本的数据结构可能略有差异,因此很难跨不同版本的 Elasticsearch 保持兼容。
- 灵活度低: RestHighLevelClient 的灵活性扩展性较差,很难去扩展或者自定义一些功能。
而 Spring 官方对 Elasticsearch 客户端也进行了封装,集成于 spring-boot-starter-data-elasticsearch 模块,Elasticsearch 官方决定废弃 RestHighLevelClient 而支持 ElasticsearchClient 这一举措,必然也导致 Spring 项目组对 data-elasticserach 模块进行同步更新,以下是 Spring 成员对相关内容的讨论:
- https://github.com/spring-projects/spring-boot/issues/28597
大概内容就是在对 ElasticsearchClient 自动装配的支持会在 springboot 3.0.x 版本中体现,而在 2.7.x 版本中会将 RestHighLevelClient 标记为废弃的。
由于我们的项目是基于 springboot 2.7.10 版本开发的,而 2.7.x 作为最后一个 2.x 版本,springboot 下个版本为 3.x,恰逢项目已经规划在半年后将 JDK 升级为17版本,全面支持 springboot 3.x 版本的替换,因此现阶段需要封装一个能够跨 2.7.x 和 3.x 版本都可以使用的 Elasticsearch 客户端。
2. 自定义 starter 模块实现 ElasticsearchTemplate 的自动装配
在调研了 spring-boot 2.7.10 版本的源码后发现,其实 2.7.x 版本已经引入了 ElasticsearchClient,并封装了新的客户端 ElasticsearchTemplate,但是并没有为其做自动装配,如果想要使用基于ElasticsearchClient 的 ElasticsearchTemplate,需要用户自己装配。否则,直接使用 ElasticsearchTemplate 会出现以下提示:
Consider defining a bean of type 'org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate' in your configuration.
即由提示可以知道,无法创建一个 ElasticsearchTemplate 类型的 bean.
因此需要自己实现 ElasticsearchTemplate 的装配,才可以使用。为了能够一次装配多项目复用,决定自己构建一个starter,之后需要使用 ElasticsearchTemplate,可以通过引入依赖的方式完成自动装配。
自定义的 starter 项目目录结构如下图所示:

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><description>自定义elasticsearch-client组件</description><parent><artifactId>xxx-spring-boot-starters</artifactId><groupId>com.xxx.commons</groupId><version>${revision}</version></parent><artifactId>xxx-elasticsearch-client-spring-boot-starter</artifactId><packaging>jar</packaging><name>xxx-elasticsearch-client-spring-boot-starter</name><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId><exclusions><exclusion><groupId>jakarta.json</groupId><artifactId>jakarta.json-api</artifactId></exclusion></exclusions></dependency><dependency><groupId>jakarta.json</groupId><artifactId>jakarta.json-api</artifactId><version>2.0.1</version></dependency></dependencies>
</project>
org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件
com.xxx.commons.springboot.elasticsearch.ElasticsearchTemplateAutoConfiguration
com.xxx.commons.springboot.elasticsearch.actuate.xxxElasticsearchHealthIndicatorAutoConfiguration
PackageInfo 接口:
package com.xxx.commons.springboot.elasticsearch;/*** @author reader* Date: 2023/9/18 22:21**/
public interface PackageInfo {
}
RestClientBuilder 类:
package com.xxx.commons.springboot.elasticsearch;import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;import java.net.URI;
import java.net.URISyntaxException;/*** @author reader* Date: 2023/9/20 15:16**/
public final class RestClientBuilder {private RestClientBuilder() {}public static RestClient buildWithProperties(ElasticsearchProperties properties) {HttpHost[] hosts = properties.getUris().stream().map(RestClientBuilder::createHttpHost).toArray((x$0) -> new HttpHost[x$0]);org.elasticsearch.client.RestClientBuilder builder = RestClient.builder(hosts);builder.setDefaultHeaders(new BasicHeader[]{new BasicHeader("Content-type", "application/json")});builder.setHttpClientConfigCallback((httpClientBuilder) -> {httpClientBuilder.addInterceptorLast((HttpResponseInterceptor) (response, context) -> response.addHeader("X-Elastic-Product", "Elasticsearch"));if (hasCredentials(properties.getUsername(), properties.getPassword())) {// 密码配置CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword()));httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);}// httpClient配置return httpClientBuilder;});builder.setRequestConfigCallback((requestConfigBuilder) -> {// request配置requestConfigBuilder.setConnectionRequestTimeout((int)properties.getConnectionTimeout().getSeconds() * 1000);requestConfigBuilder.setSocketTimeout((int)properties.getSocketTimeout().getSeconds() * 1000);return requestConfigBuilder;});if (properties.getPathPrefix() != null) {builder.setPathPrefix(properties.getPathPrefix());}return builder.build();}private static boolean hasCredentials(String username, String password) {return StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password);}private static HttpHost createHttpHost(String uri) {try {return createHttpHost(URI.create(uri));} catch (IllegalArgumentException var2) {return HttpHost.create(uri);}}private static HttpHost createHttpHost(URI uri) {if (StringUtils.isBlank(uri.getUserInfo())) {return HttpHost.create(uri.toString());} else {try {return HttpHost.create((new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())).toString());} catch (URISyntaxException var2) {throw new IllegalStateException(var2);}}}
}
ElasticsearchClientConfiguration 类:
package com.xxx.commons.springboot.elasticsearch;import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author reader* Date: 2023/9/20 14:59**/
@Configuration
@EnableConfigurationProperties({ElasticsearchProperties.class})
@ConditionalOnClass({ElasticsearchClient.class, ElasticsearchTransport.class})
public class ElasticsearchClientConfiguration {protected static final Log LOGGER = LogFactory.getLog(ElasticsearchClientConfiguration.class);private ElasticsearchProperties elasticsearchProperties;public ElasticsearchClientConfiguration(ElasticsearchProperties elasticsearchProperties) {LOGGER.info("框架 elasticsearch-client-starter elasticsearchProperties 装载开始");this.elasticsearchProperties = elasticsearchProperties;}@Beanpublic ElasticsearchClient elasticsearchClient() {LOGGER.info("框架 elasticsearch-client-starter elasticsearchClient 装载开始");RestClient restClient = RestClientBuilder.buildWithProperties(elasticsearchProperties);RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());return new ElasticsearchClient(transport);}
}
package com.xxx.commons.springboot.elasticsearch;import co.elastic.clients.elasticsearch.ElasticsearchClient;
import com.xxx.commons.springboot.elasticsearch.actuate.ElasticsearchInfoContributor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.info.ConditionalOnEnabledInfoContributor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @author reader* Date: 2023/9/19 16:35**/
@AutoConfiguration(before = {ElasticsearchRestClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class})
@ConditionalOnClass({ElasticsearchTemplate.class})
@EnableConfigurationProperties({ElasticsearchProperties.class})
@Import({ElasticsearchClientConfiguration.class})
public class ElasticsearchTemplateAutoConfiguration {protected static final Log LOGGER = LogFactory.getLog(ElasticsearchTemplateAutoConfiguration.class);@BeanElasticsearchCustomConversions elasticsearchCustomConversions() {return new ElasticsearchCustomConversions(Collections.emptyList());}@Beanpublic SimpleElasticsearchMappingContext elasticsearchMappingContext(ApplicationContext applicationContext,ElasticsearchCustomConversions elasticsearchCustomConversions) throws ClassNotFoundException {SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();mappingContext.setInitialEntitySet(new EntityScanner(applicationContext).scan(Document.class));mappingContext.setSimpleTypeHolder(elasticsearchCustomConversions.getSimpleTypeHolder());return mappingContext;}@BeanElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext,ElasticsearchCustomConversions elasticsearchCustomConversions) {MappingElasticsearchConverter converter = new MappingElasticsearchConverter(mappingContext);converter.setConversions(elasticsearchCustomConversions);return converter;}@BeanElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient client, ElasticsearchConverter converter) {LOGGER.info("框架 elasticsearch-client-starter elasticsearchTemplate 装载开始");return new ElasticsearchTemplate(client, converter);}@Bean@ConditionalOnEnabledInfoContributor("elasticsearch")public ElasticsearchInfoContributor elasticsearchInfoContributor(ObjectProvider<ElasticsearchProperties> propertiesObjectProvider) {List<ElasticsearchProperties> properties = new ArrayList<>();propertiesObjectProvider.forEach(properties::add);return new ElasticsearchInfoContributor(properties);}
}
健康度指标相关的封装有:
- ElasticsearchHealthIndicator 类:
package com.xxx.commons.springboot.elasticsearch.actuate;import org.elasticsearch.client.Node;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @author reader* Date: 2023/9/20 19:26**/
public class ElasticsearchHealthIndicator extends AbstractHealthIndicator {private final List<RestClient> clients;public ElasticsearchHealthIndicator(List<RestClient> clients) {this.clients = clients;}@Overrideprotected void doHealthCheck(Health.Builder builder) throws Exception {boolean success = true;Map<String, Object> properties = new HashMap<>();for (RestClient client : clients) {List<Node> nodes = client.getNodes();if (null == nodes || nodes.isEmpty()){continue;}String id = nodes.stream().map(Node::toString).collect(Collectors.joining(";"));boolean ps = client.isRunning();properties.put("ElasticsearchClient[" + id + "]", ps);if (!ps) {success = false;}}if (success) {builder.up();} else {builder.withDetails(properties).down();}}
}
- ElasticsearchInfoContributor 类:
package com.xxx.commons.springboot.elasticsearch.actuate;import com.xxx.commons.springboot.elasticsearch.PackageInfo;
import org.springframework.boot.actuate.info.Info;
import org.springframework.boot.actuate.info.InfoContributor;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author reader* Date: 2023/9/20 19:32**/
public class ElasticsearchInfoContributor implements InfoContributor {private final List<ElasticsearchProperties> elasticsearchProperties;public ElasticsearchInfoContributor(List<ElasticsearchProperties> elasticsearchProperties) {this.elasticsearchProperties = elasticsearchProperties;}@Overridepublic void contribute(Info.Builder builder) {Map<String, Object> properties = new HashMap<>();properties.put("version", PackageInfo.class.getPackage().getImplementationVersion());properties.put("_title_", "ElasticsearchTemplate组件");elasticsearchProperties.forEach(p -> {Map<String, Object> sp = new HashMap<>();String id = String.join(";", p.getUris());properties.put(id, sp);sp.put("nodes", String.join(";", p.getUris()));sp.put("user", p.getUsername());sp.put("connectionTimeout[ms]", p.getConnectionTimeout().toMillis());sp.put("socketTimeout[ms]", p.getSocketTimeout().toMillis());});builder.withDetail("xxx-elasticsearch-client", properties);}
}
- xxxElasticsearchHealthIndicatorAutoConfiguration 类:
package com.xxx.commons.springboot.elasticsearch.actuate;import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;import java.util.ArrayList;
import java.util.List;/*** @author reader* Date: 2023/9/20 19:45**/
@AutoConfiguration(before = {HealthContributorAutoConfiguration.class})
@ConditionalOnEnabledHealthIndicator("elasticsearch")
public class xxxElasticsearchHealthIndicatorAutoConfiguration {@Bean("elasticsearchHealthIndicator")@ConditionalOnMissingBeanpublic ElasticsearchHealthIndicator xxxElasticHealthIndicator(ObjectProvider<RestClient> elasticsearchClientProvider) {List<RestClient> restClients = new ArrayList<>();elasticsearchClientProvider.forEach(restClients::add);return new ElasticsearchHealthIndicator(restClients);}
}
3. 使用自定义的 starter
1、在自己封装了一个 starter 工具模块之后,通过引入依赖的方式使用,引入的依赖为:
<dependency><groupId>com.xxx.commons</groupId><artifactId>xxx-elasticsearch-client-spring-boot-starter</artifactId><version>${version}</version>
</dependency>
在 yaml 文件中配置的相关属性信息:
spring:elasticsearch:uris: http://127.0.0.1:9200 username: elasticpassword: password
注入并使用 ElasticsearchTemplate 对 ES 进行操作:
package com.xxx.xxx;import com.xxx.commons.result.query.PaginationBuilder;
import com.xxx.commons.result.query.Query;
import com.xxx.commons.result.query.QueryBuilder;
import com.xxx.push.domain.AliPushRecordDO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.CollectionUtils;import java.util.ArrayList;
import java.util.List;/*** @author reader* Date: 2023/9/26 14:42**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, properties = {"profile=dev", "debug=true"})
public class ElasticsearchTemplateTest {@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;@Testpublic void testSearch() {Query query = QueryBuilder.page(1).pageSize(20).build();NativeQueryBuilder nativeQueryBuilder = new NativeQueryBuilder();nativeQueryBuilder.withPageable(PageRequest.of(query.getPage() - 1, query.getPageSize()));NativeQuery searchQuery = nativeQueryBuilder.build();// 查询总数long count = elasticsearchTemplate.count(searchQuery, AliPushRecordDO.class);PaginationBuilder<AliPushRecordDO> builder = PaginationBuilder.query(query);builder.amount((int) count);if (count > 0) {SearchHits<AliPushRecordDO> aliPushRecordDOSearchHits = elasticsearchTemplate.search(searchQuery, AliPushRecordDO.class);List<SearchHit<AliPushRecordDO>> searchHits = aliPushRecordDOSearchHits.getSearchHits();List<AliPushRecordDO> aliPushRecordDOList = new ArrayList<>();if (!CollectionUtils.isEmpty(searchHits)) {searchHits.forEach(searchHit -> aliPushRecordDOList.add(searchHit.getContent()));}builder.result(aliPushRecordDOList);} else {builder.result(new ArrayList<>());}}
}
相关文章:
基于 SpringBoot 2.7.x 使用最新的 Elasticsearch Java API Client 之 ElasticsearchClient
1. 从 RestHighLevelClient 到 ElasticsearchClient 从 Java Rest Client 7.15.0 版本开始,Elasticsearch 官方决定将 RestHighLevelClient 标记为废弃的,并推荐使用新的 Java API Client,即 ElasticsearchClient. 为什么要将 RestHighLevelC…...
辅助驾驶功能开发-功能对标篇(15)-NOA领航辅助系统-吉利
1.横向对标参数 厂商吉利车型FX11/EX11/DCY11/G636上市时间2022Q4方案6V5R+1DMS摄像头前视摄像头1*(8M)侧视摄像头/后视摄像头1环视摄像头4DMS摄像头1雷达毫米波雷达54D毫米波雷达/超声波雷达12激光雷达/域控供应商福瑞泰克辅助驾驶软件供应商福瑞泰克高精度地图百度芯片TDA4 T…...
javascript: Sorting Algorithms
// Sorting Algorithms int JavaScript https://www.geeksforgeeks.org/sorting-algorithms/ /** * file Sort.js * 1. Bubble Sort冒泡排序法 * param arry * param nszie */ function BubbleSort(arry, nszie) {var i, j, temp;var swapped;for (i 0; i < nszie - 1; i)…...
嵌入式Linux应用开发-驱动大全-同步与互斥④
嵌入式Linux应用开发-驱动大全-同步与互斥④ 第一章 同步与互斥④1.5 自旋锁spinlock的实现1.5.1 自旋锁的内核结构体1.5.2 spinlock在UP系统中的实现1.5.3 spinlock在SMP系统中的实现 1.6 信号量semaphore的实现1.6.1 semaphore的内核结构体1.6.2 down函数的实现1.6.3 up函数的…...
2023年【高压电工】证考试及高压电工复审模拟考试
题库来源:安全生产模拟考试一点通公众号小程序 高压电工证考试根据新高压电工考试大纲要求,安全生产模拟考试一点通将高压电工模拟考试试题进行汇编,组成一套高压电工全真模拟考试试题,学员可通过高压电工复审模拟考试全真模拟&a…...
C/C++学习 -- 分组密算法(3DES算法)
1. 3DES算法概述 3DES(Triple Data Encryption Standard),又称为TDEA(Triple Data Encryption Algorithm),是一种对称加密算法,是DES(Data Encryption Standard)的加强版…...
C/C++面试题总结
1.new与malloc的区别 new操作符从自由存储区上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。 使用new操作符申请内存分配时无须指定内存块的大小,而malloc则需要显式地指出所需内存的尺寸。 int *p new int; delete p;//一定要配对使用n…...
Java下正面解除警告Unchecked cast: ‘java.lang.Object‘ to ‘java.util.ArrayList‘
就是我在反序列化时,遇到这样一个警告: Unchecked cast: java.lang.Object to java.util.ArrayList<com.work1.Student>然后我去网上查,有些人说用SuppressWarnings(“unchecked”)去忽略警告,但是我觉得作为一名合格的程序…...
图像处理与计算机视觉--第四章-图像滤波与增强-第二部分
目录 1.图像噪声化处理与卷积平滑 2.图像傅里叶快速变换处理 3.图像腐蚀和膨胀处理 4 图像灰度调整处理 5.图像抖动处理算法 学习计算机视觉方向的几条经验: 1.学习计算机视觉一定不能操之过急,不然往往事倍功半! 2.静下心来,理解每一个…...
[前端基础]typescript安装以及类型拓展
(0)写在前面: 作者之前都是在写js,所以这里介绍ts肯定是不能从头开始介绍了,主要在js的基础上介绍ts关于类型的几个特性,以及ts的安装还有配置问题 (1)ts和js是什么关系 通俗点来…...
网络参考资料汇总(1)
将这段时间参考的各路大佬的资料加以汇总分类: (1)FFmpeg: 基于FFmpeg进行rtsp推流及拉流(详细教程) Linux 编译安装 FFmpeg 步骤(带ffplay) Jetson 环境安装(三):jetson nano配置ffmpeg和ngin…...
Remove和RemoveLast用法
LeetCode 46 全排列 先贴代码 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> temp new ArrayList<>();public List<List<Integer>> permute(int[] nums) {dfs(nums, 0);return result;}public v…...
(一) 使用 Hugo 搭建个人博客保姆级教程(上篇)
手把手教你如何从0开始构建一个静态网站,这不需要有太多的编程和开发经验和时间投入,也基本不需要多少成本(除了个性化域名),使用GitHub和Hugo模板即可快速构建和上线一个网站。 目标读者 本文档适用于以下用户&…...
数据结构之栈
栈的模拟实现 1.栈的概念2.栈的方法3.栈的模拟实现(代码)3.1 接口My_Stack3.2 StackList3.3 异常类StackException3.4 测试类Test 1.栈的概念 2.栈的方法 3.栈的模拟实现(代码) 3.1 接口My_Stack 3.2 StackList 3.3 异常类StackException 3.4 测试类Test...
wireshark of tshark tools v3.4.0版本 支持json
tshark(1) Install tshark (Wireshark) Ver.3.4.0 on CentOS7 --It must be "ps", "text", "pdml", "psml" or "fields". TCP 协议中的三次握手和四次挥手是 TCP 连接建立和关闭的过程。 三次握手 客户端向服务器发送 SYN…...
Python开源项目月排行 2023年9月
#2023年9月2023年9月9日1fishdraw这个项目是用来随机生成一条鱼的,这条鱼特别的稀奇古怪,这个项目不依赖任何库,支持 svg, json, csv 等格式。2vizro一个用于创建模块化数据可视化应用程序的工具包。在几分钟内快速自助组装定制仪表板 - 无需…...
uniapp项目实践总结(二十五)苹果 ios 平台 APP 打包教程
导语:当你的应用程序开发完成后,在上架 ios 应用商店之前,需要进行打包操作,下面就简单介绍一下打包方法。 目录 准备工作注册账号生成证书打包配置准备工作 在打包之前,请保证你的 uniapp 应用程序编译到 ios 模拟器或者是真机调试基座环境下是可以正常运行的,苹果打包…...
MySQL查询(基础到高级)
一、单表查询: 1.基本查询: 1.1 查询多个字段: 1.查询所有字段: select * from 表名;2.查询指定字段: select 字段1,字段2 from 表名; 1.2 去除重复记录 select distinct "字段" FROM "表名"; …...
电脑通过串口助手和51单片机串口通讯
今天有时间把电脑和51单片机之间的串口通讯搞定了,电脑发送的串口数据,单片机能够正常接收并显示到oled屏幕上,特此记录一下,防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧! 下面是串口3.c的文件全部内容&a…...
【Linux】线程详解完结篇——信号量 + 线程池 + 单例模式 + 读写锁
线程详解第四篇 前言正式开始信号量引例信号量的本质信号量相关的四个核心接口生产消费者模型用环形队列实现生产者消费者模型基于环形队列的生产消费模型的原理代码演示单生产者单消费者多生产者多消费者 计数器的意义 线程池基本概念代码 单例模式STL,智能指针和线程安全STL中…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
