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

基于 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 版本开始&#xff0c;Elasticsearch 官方决定将 RestHighLevelClient 标记为废弃的&#xff0c;并推荐使用新的 Java API Client&#xff0c;即 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年【高压电工】证考试及高压电工复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工证考试根据新高压电工考试大纲要求&#xff0c;安全生产模拟考试一点通将高压电工模拟考试试题进行汇编&#xff0c;组成一套高压电工全真模拟考试试题&#xff0c;学员可通过高压电工复审模拟考试全真模拟&a…...

C/C++学习 -- 分组密算法(3DES算法)

1. 3DES算法概述 3DES&#xff08;Triple Data Encryption Standard&#xff09;&#xff0c;又称为TDEA&#xff08;Triple Data Encryption Algorithm&#xff09;&#xff0c;是一种对称加密算法&#xff0c;是DES&#xff08;Data Encryption Standard&#xff09;的加强版…...

C/C++面试题总结

1.new与malloc的区别 new操作符从自由存储区上为对象动态分配内存空间&#xff0c;而malloc函数从堆上动态分配内存。 使用new操作符申请内存分配时无须指定内存块的大小&#xff0c;而malloc则需要显式地指出所需内存的尺寸。 int *p new int; delete p;//一定要配对使用n…...

Java下正面解除警告Unchecked cast: ‘java.lang.Object‘ to ‘java.util.ArrayList‘

就是我在反序列化时&#xff0c;遇到这样一个警告&#xff1a; Unchecked cast: java.lang.Object to java.util.ArrayList<com.work1.Student>然后我去网上查&#xff0c;有些人说用SuppressWarnings(“unchecked”)去忽略警告&#xff0c;但是我觉得作为一名合格的程序…...

图像处理与计算机视觉--第四章-图像滤波与增强-第二部分

目录 1.图像噪声化处理与卷积平滑 2.图像傅里叶快速变换处理 3.图像腐蚀和膨胀处理 4 图像灰度调整处理 5.图像抖动处理算法 学习计算机视觉方向的几条经验: 1.学习计算机视觉一定不能操之过急&#xff0c;不然往往事倍功半&#xff01; 2.静下心来&#xff0c;理解每一个…...

[前端基础]typescript安装以及类型拓展

&#xff08;0&#xff09;写在前面&#xff1a; 作者之前都是在写js&#xff0c;所以这里介绍ts肯定是不能从头开始介绍了&#xff0c;主要在js的基础上介绍ts关于类型的几个特性&#xff0c;以及ts的安装还有配置问题 &#xff08;1&#xff09;ts和js是什么关系 通俗点来…...

网络参考资料汇总(1)

将这段时间参考的各路大佬的资料加以汇总分类&#xff1a; &#xff08;1&#xff09;FFmpeg: 基于FFmpeg进行rtsp推流及拉流&#xff08;详细教程&#xff09; Linux 编译安装 FFmpeg 步骤&#xff08;带ffplay&#xff09; 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开始构建一个静态网站&#xff0c;这不需要有太多的编程和开发经验和时间投入&#xff0c;也基本不需要多少成本&#xff08;除了个性化域名&#xff09;&#xff0c;使用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这个项目是用来随机生成一条鱼的&#xff0c;这条鱼特别的稀奇古怪&#xff0c;这个项目不依赖任何库&#xff0c;支持 svg, json, csv 等格式。2vizro一个用于创建模块化数据可视化应用程序的工具包。在几分钟内快速自助组装定制仪表板 - 无需…...

uniapp项目实践总结(二十五)苹果 ios 平台 APP 打包教程

导语:当你的应用程序开发完成后,在上架 ios 应用商店之前,需要进行打包操作,下面就简单介绍一下打包方法。 目录 准备工作注册账号生成证书打包配置准备工作 在打包之前,请保证你的 uniapp 应用程序编译到 ios 模拟器或者是真机调试基座环境下是可以正常运行的,苹果打包…...

MySQL查询(基础到高级)

一、单表查询&#xff1a; 1.基本查询&#xff1a; 1.1 查询多个字段&#xff1a; 1.查询所有字段&#xff1a; select * from 表名;2.查询指定字段&#xff1a; select 字段1,字段2 from 表名; 1.2 去除重复记录 select distinct "字段" FROM "表名"; …...

电脑通过串口助手和51单片机串口通讯

今天有时间把电脑和51单片机之间的串口通讯搞定了&#xff0c;电脑发送的串口数据&#xff0c;单片机能够正常接收并显示到oled屏幕上&#xff0c;特此记录一下&#xff0c;防止后面自己忘记了怎么搞得了。 先来两个图片看看结果吧&#xff01; 下面是串口3.c的文件全部内容&a…...

【Linux】线程详解完结篇——信号量 + 线程池 + 单例模式 + 读写锁

线程详解第四篇 前言正式开始信号量引例信号量的本质信号量相关的四个核心接口生产消费者模型用环形队列实现生产者消费者模型基于环形队列的生产消费模型的原理代码演示单生产者单消费者多生产者多消费者 计数器的意义 线程池基本概念代码 单例模式STL,智能指针和线程安全STL中…...

弧度、圆弧上的点、圆的半径(r)、弧长(s)之间的关系

要计算弧度和圆弧上的点&#xff0c;需要知道以下几个要素&#xff1a; 圆的半径&#xff08;r&#xff09;&#xff1a;即圆的中心到圆周上任意一点的距离。 弧长&#xff08;s&#xff09;&#xff1a;从圆周上的一个点到另一个点所经过的弧长。 弧度&#xff08;θ&#x…...

[AOSP] [JNI] [Android] AOSP中使用JNI

一. 简要 &#x1f34e; JNI是Java Native Interface的缩写&#xff0c;它提供了若干的API实现了Java和其他语言的通信&#xff08;主要是C&C&#xff09;。从Java1.1开始&#xff0c;JNI标准成为java平台的一部分&#xff0c;它允许Java代码和其他语言写的代码进行交互。J…...

GEE案例——如何使用长时序影像实现多波段图像加载(不同层土壤湿度)

简介: 在GEE中实现时序图像的加载主要的目的是查看影像波段或者指数的变化,这里我们使用的主要是加载常规的4个波段,然后添加一个复合波段,复合波段主要的是求4个波段的平均值,然后再次加入到原有的4个波段的时序图中。这里面主要的技术难点一个是图表的设定,另外一个就…...

Cloudflare进阶技巧:缓存利用最大化

1. 引言 cloudflare我想你应该知道是什么&#xff0c;一家真正意义上免费无限量的CDN&#xff0c;至今未曾有哥们喷它的。当然&#xff0c;在国内的速度确实比较一般&#xff0c;不过这也不能怪它。 CDN最大的特色&#xff0c;我想就是它的缓存功能&#xff0c;达到防攻击&am…...

想要精通算法和SQL的成长之路 - 二叉树的判断问题(子树判断 | 对称性 | 一致性判断)

想要精通算法和SQL的成长之路 - 二叉树的判断问题 前言一. 相同的树二. 对称二叉树三. 判断子树 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 相同的树 原题链接 这题目典型的递归题&#xff1a; 如果两个节点都是null&#xff0c;我们返回true。如果两个节点一个nul…...

(零)如何做机器视觉项目

文章目录 1 项目的前期准备1.1 从5个方面初步分析客户需求1.2 方案评估与验证1.3 签订合同 2 项目规划2.1 定义客户端的详细需求2.2 制定项目管理计划2.3 方案评审 3 详细设计3.1 硬件设备的选择与环境搭建3.2 软件开发平台与开发工具的选择3.3 机器视觉系统的整体框架与开发流…...

【Leetcode】滑动窗口合集

这里写目录标题 209.长度最小的子数组题目思路代码 3. 无重复字符的最长子串&#xff08;medium&#xff09;题目思路 11. 最大连续 1 的个数 III题目思路 1658. 将 x 减到 0 的最⼩操作数题目思路代码 904. 水果成篮题目思路代码 438.找到字符串中所有字母的异位词题目思路代码…...

【C++】STL详解(九)—— set、map、multiset、multimap的介绍及使用

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C学习 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C】STL…...

计组—— I/O系统

&#x1f4d5;&#xff1a;参考王道课件 目录 一、I/O系统的基本概念 1.什么是“I/O”&#xff1f; ​编辑2.主机如何和I/O设备进行交互&#xff1f; 3.I/O控制方式 &#xff08;1&#xff09;程序查询方式 &#xff08;2&#xff09;程序中断方式 &#xff08;3&#x…...

基于vc6+sdk51开发简易文字识别转语音的程序

系统&#xff1a;window7 软件&#xff1a;vc6.0 目的&#xff1a;简易文字转语音真人发声 利用2023国庆小长假&#xff0c;研究如何将文言转语音&#xff0c;之前在网上查询相关知识&#xff0c;大致了解微信语音转换&#xff0c;翻译官之类软件的原理&#xff0c;但要加入神…...

wordpress 主页布局/nba赛季排名

RCF的使用教程 RCF(Remote Call Framework)是一个使用C编写的RPC框架&#xff0c;在底层RCF支持多种传输实现方式(transport implementations). 包括TCP&#xff0c;UDP&#xff0c;多播&#xff0c;组播&#xff0c;win32命名管道和unix domain socket。下面我以一个例子讲述…...

wordpress 被镜像/汕头seo排名公司

1. 学好学通c语言的许多种理由单片机需要C语言Java及C#和C语言很像Python是C语言的封装嵌入式Linux编程和开发需要C语言Javascript语言和C语言很像C和C语言很像C语言比汇编容易学……C语言可以引导人们开启编程的大门&#xff0c;教给人们计算机编程的套路&#xff0c;更加彻底…...

做游戏网站用什么系统做/百度模拟点击软件判刑了

thinkphp3.2.3(5以下)的addAll返回值问题thinkphp3.2.3(5以下)的addAll返回值问题[var1]我们都知道mysql支持一次插入多条数据&#xff0c;如下&#xff1a;以用户表user为例&#xff0c;表结构自增主键id、账号username、密码password。insert into user(username,password) v…...

创建企业手机微信网站门户/百度客服怎么转人工电话

1.UIBarButtonItem 放置在toolbar或uinavigationitem上&#xff0c;可以设置点击item触发的方法调用&#xff1b; 初始化方法&#xff1a; - (instancetype)initWithCustomView:(UIView *)customView; --用自定义view初始化- (instancetype)initWithImage:(UIImage *)image st…...

海外网站服务器网址/中国500强最新排名

异或运算法则   1. a ^ b b ^ a 2. a ^ b ^ c a ^ (b ^ c) (a ^ b) ^ c; 3. d a ^ b ^ c 可以推出 a d ^ b ^ c. 4. a ^ b ^ a b. 异或运算 1、异或是一个数学运算符。应用于逻辑运算。 2、例如&#xff1a;真异或假的结果是真&#xff0c;假异或真的结果也是真&#x…...

做贺卡 网站/目录搜索引擎有哪些

windows中安装配置MySQL 5.7.26 一. 下载MySQL https://dev.mysql.com/downloads/mysql/ &#xfffc; 下载完成后后,解压缩即可.&#xfffc; 讲解压后的文件,移动到某个盘符下,比如E盘.&#xfffc; 二. 配置my.ini 在mysql-5.7.26解压目录下,创建一个my.ini文件 文件…...