java与es8实战之四:SpringBoot应用中操作es8(无安全检查)

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本篇是《java与es8实战》系列的第四篇,系列文章写到现在,连个HelloWorld都没运行起来,实在说不过去了...
  • 因此,本篇总体目标明确:实战在SpringBoot应用中操作elasticsearch8
  • 为了降低难度,本篇部署的elasticsearch8未设置安全检查,无需证书、账号、密码,只要连接到es的IP和端口就能执行操作
  • 总体目标可以拆解为两个子任务
  1. 在SpringBoot中连接elasticsearch8
  2. 在SpringBoot中使用elasticsearch8官方的Java API Client
  • 接下来直接开始

部署elasticsearch集群(无安全检查)

Java应用连接elasticsearch的核心套路

  • 不论是直连,还是带安全检查的连接,亦或是与SpringBoot的集成使之更方便易用,都紧紧围绕着一个不变的核心套路,该套路由两部分组成,掌握了它们就能在各种条件下成功连接es
  1. 首先,是builder pattern,连接es有关的代码,各种对象都是其builder对象的build方法创建的,建议您提前阅读《java与es8实战之一》一文,看完后,满屏的builder代码可以从丑变成美...
  2. 其次,就是java应用能向es发请求的关键:ElasticsearchClient对象,该对象的创建是有套路的,如下图,先创建RestClient,再基于RestClient创建ElasticsearchTransport,最后基于ElasticsearchTransport创建ElasticsearchClient,这是个固定的套路,咱们后面的操作都是基于此的,可能会加一点东西,但不会改变流程和图中的对象
    java与es8实战之四:SpringBoot应用中操作es8(无安全检查)
  • 准备完毕,开始写代码

新建子工程

  • 为了便于管理依赖库版本和源码,《java与es8实战》系列的所有代码都以子工程的形式存放在父工程elasticsearch-tutorials

  • 《java与es8实战之二:实战前的准备工作》一文说明了创建父工程的详细过程

  • 在父工程elasticsearch-tutorials中新建名为basic-crud的子工程,其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">     <!-- 请改为自己项目的parent坐标 -->     <parent>         <artifactId>elasticsearch-tutorials</artifactId>         <groupId>com.bolingcavalry</groupId>         <version>1.0-SNAPSHOT</version>         <relativePath>../pom.xml</relativePath>     </parent>     <modelVersion>4.0.0</modelVersion>     <!-- 请改为自己项目的artifactId -->     <artifactId>basic-crud</artifactId>     <packaging>jar</packaging>     <!-- 请改为自己项目的name -->     <name>basic-crud</name>     <url>https://github.com/zq2599</url>      <!--不用spring-boot-starter-parent作为parent时的配置-->     <dependencyManagement>         <dependencies>             <dependency>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-dependencies</artifactId>                  <version>${springboot.version}</version>                 <type>pom</type>                 <scope>import</scope>             </dependency>         </dependencies>     </dependencyManagement>      <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-actuator</artifactId>         </dependency>          <!-- 不加这个,configuration类中,IDEA总会添加一些提示 -->         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-configuration-processor</artifactId>             <optional>true</optional>         </dependency>          <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>         </dependency>          <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>          <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>              <!-- exclude junit 4 -->             <exclusions>                 <exclusion>                     <groupId>junit</groupId>                     <artifactId>junit</artifactId>                 </exclusion>             </exclusions>          </dependency>          <!-- junit 5 -->         <dependency>             <groupId>org.junit.jupiter</groupId>             <artifactId>junit-jupiter-api</artifactId>             <scope>test</scope>         </dependency>          <dependency>             <groupId>org.junit.jupiter</groupId>             <artifactId>junit-jupiter-engine</artifactId>             <scope>test</scope>         </dependency>          <!-- elasticsearch引入依赖  start -->         <dependency>             <groupId>co.elastic.clients</groupId>             <artifactId>elasticsearch-java</artifactId>         </dependency>          <dependency>             <groupId>com.fasterxml.jackson.core</groupId>             <artifactId>jackson-databind</artifactId>         </dependency>          <!-- 使用spring boot Maven插件时需要添加该依赖 -->         <dependency>             <groupId>jakarta.json</groupId>             <artifactId>jakarta.json-api</artifactId>         </dependency>          <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>     </dependencies>      <build>         <plugins>             <!-- 需要此插件,在执行mvn test命令时才会执行单元测试 -->             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-surefire-plugin</artifactId>                 <version>3.0.0-M4</version>                 <configuration>                     <skipTests>false</skipTests>                 </configuration>             </plugin>              <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>                 <configuration>                     <excludes>                         <exclude>                             <groupId>org.projectlombok</groupId>                             <artifactId>lombok</artifactId>                         </exclude>                     </excludes>                 </configuration>             </plugin>         </plugins>          <resources>             <resource>                 <directory>src/main/resources</directory>                 <includes>                     <include>**/*.*</include>                 </includes>             </resource>         </resources>     </build> </project> 

编码:配置文件

  • 先准备好配置文件application.yml,内容如下,很简单,只有es的地址信息
elasticsearch:   # 多个IP逗号隔开   hosts: 127.0.0.1:9200 

编码:配置类

  • 首先把启动类写好,平平无奇的启动类BasicCrudApplication.java
@SpringBootApplication public class BasicCrudApplication {     public static void main(String[] args) {         SpringApplication.run(BasicCrudApplication.class, args);     } } 
  • 然后是配置类ClientConfig.java,这是本篇的关键,操作ES所需的ElasticsearchClient实例如何创建,ES的IP地址如何传入,全部写在这里了
package com.bolingcavalry.basic.config;  import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.rest_client.RestClientTransport; import lombok.Setter; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils;  @ConfigurationProperties(prefix = "elasticsearch") //配置的前缀 @Configuration public class ClientConfig {      @Setter     private String hosts;      /**      * 解析配置的字符串,转为HttpHost对象数组      * @return      */     private HttpHost[] toHttpHost() {         if (!StringUtils.hasLength(hosts)) {             throw new RuntimeException("invalid elasticsearch configuration");         }          String[] hostArray = hosts.split(",");         HttpHost[] httpHosts = new HttpHost[hostArray.length];         HttpHost httpHost;         for (int i = 0; i < hostArray.length; i++) {             String[] strings = hostArray[i].split(":");             httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");             httpHosts[i] = httpHost;         }          return httpHosts;     }      @Bean     public ElasticsearchClient elasticsearchClient() {         HttpHost[] httpHosts = toHttpHost();         RestClient restClient = RestClient.builder(httpHosts).build();         RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());         return new ElasticsearchClient(transport);     }      @Bean     public ElasticsearchAsyncClient elasticsearchAsyncClient() {         HttpHost[] httpHosts = toHttpHost();         RestClient restClient = RestClient.builder(httpHosts).build();         RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());         return new ElasticsearchAsyncClient(transport);     } } 
  • 从上面的代码可以看出,配置类已经向Spring容器注册了ElasticsearchClient实例,后面的业务都可以使用此实例来操作ES

编码:服务类

  • 本篇只是为了演示SpringBoot应用如何连接和操作ES,还不会深入ES操作的细节,因此只对索引做一些基本操作即可

  • 先写一个接口IndexService.java,里面定义了多个索引操作的方法

package com.bolingcavalry.basic.service;  import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; import co.elastic.clients.elasticsearch.indices.IndexSettings; import co.elastic.clients.util.ObjectBuilder;  import java.io.IOException; import java.util.function.Function;  public interface IndexService {      /**      * 新建指定名称的索引      * @param name      * @throws IOException      */     void addIndex(String name) throws IOException;      /**      * 检查指定名称的索引是否存在      * @param name      * @return      * @throws IOException      */     boolean indexExists(String name) throws IOException;      /**      * 删除指定索引      * @param name      * @throws IOException      */     void delIndex(String name) throws IOException;      /**      * 创建索引,指定setting和mapping      * @param name 索引名称      * @param settingFn 索引参数      * @param mappingFn 索引结构      * @throws IOException      */     void create(String name,                 Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,                 Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException; } 
  • 然后接口的实现,可见所有操作都是在调用ElasticsearchClient实例的API
package com.bolingcavalry.basic.service.impl;  import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; import co.elastic.clients.elasticsearch.indices.IndexSettings; import co.elastic.clients.util.ObjectBuilder; import com.bolingcavalry.basic.service.IndexService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service;  import java.io.IOException; import java.util.function.Function;  @Service public class IndexServiceImpl implements IndexService {      @Autowired     private ElasticsearchClient elasticsearchClient;      @Override     public void addIndex(String name) throws IOException {         ApplicationContext applicationContext;         elasticsearchClient.indices().create(c -> c.index(name));     }      @Override     public boolean indexExists(String name) throws IOException {         ApplicationContext a;         return elasticsearchClient.indices().exists(b -> b.index(name)).value();     }      @Override     public void delIndex(String name) throws IOException {         elasticsearchClient.indices().delete(c -> c.index(name));     }      @Override     public void create(String name,                        Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn,                        Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn) throws IOException {        elasticsearchClient                .indices()                .create(c -> c                        .index(name)                        .settings(settingFn)                        .mappings(mappingFn)                );     } } 
  • 以上就是本篇的功能代码了,连接ES在其上进行索引相关操作

编码:单元测试

  • 为了验证上述代码是否生效,接下来写一个单元测试类IndexServiceTest.java,可以重点关注createIndex方法,里面演示了Builder pattern构建参数的详细步骤
package com.bolingcavalry.basic.service;  import co.elastic.clients.elasticsearch._types.mapping.Property; import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; import co.elastic.clients.elasticsearch.indices.IndexSettings; import co.elastic.clients.util.ObjectBuilder; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;  import java.util.function.Function;  @SpringBootTest class IndexServiceTest {      @Autowired     IndexService indexService;      @Test     void addIndex() throws Exception {         String indexName = "test_index";          Assertions.assertFalse(indexService.indexExists(indexName));         indexService.addIndex(indexName);         Assertions.assertTrue(indexService.indexExists(indexName));         indexService.delIndex(indexName);         Assertions.assertFalse(indexService.indexExists(indexName));     }      @Test     void indexExists() throws Exception {         indexService.indexExists("a");     }      @Test     void createIndex() throws Exception {         // 索引名         String indexName = "product002";          // 构建setting时,builder用到的lambda         Function<IndexSettings.Builder, ObjectBuilder<IndexSettings>> settingFn = sBuilder -> sBuilder                 .index(iBuilder -> iBuilder                         // 三个分片                         .numberOfShards("3")                         // 一个副本                         .numberOfReplicas("1")                 );          // 新的索引有三个字段,每个字段都有自己的property,这里依次创建         Property keywordProperty = Property.of(pBuilder -> pBuilder.keyword(kBuilder -> kBuilder.ignoreAbove(256)));         Property textProperty = Property.of(pBuilder -> pBuilder.text(tBuilder -> tBuilder));         Property integerProperty = Property.of(pBuilder -> pBuilder.integer(iBuilder -> iBuilder));          // // 构建mapping时,builder用到的lambda         Function<TypeMapping.Builder, ObjectBuilder<TypeMapping>> mappingFn = mBuilder -> mBuilder                 .properties("name", keywordProperty)                 .properties("description", textProperty)                 .properties("price", integerProperty);          // 创建索引,并且指定了setting和mapping         indexService.create(indexName, settingFn, mappingFn);     } } 
  • 确保不做安全检查的ES集群运行正常,再执行单元测试,如下图,顺利通过,证明所有对ES的操作都符合预期
    java与es8实战之四:SpringBoot应用中操作es8(无安全检查)
  • 再用eshead观察product002索引的情况,如下图,三个分片,一个副本,与代码中设置的一致
    java与es8实战之四:SpringBoot应用中操作es8(无安全检查)
  • 至此最简单的连接和操作ES实战已经完成,希望本篇能给您一些参考,助您顺利完成基本操作

是不是线程安全的

源码下载

名称 链接 备注
项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  • 这个git项目中有多个文件夹,本次实战的源码在elasticsearch-tutorials文件夹下,如下图红框
    java与es8实战之四:SpringBoot应用中操作es8(无安全检查)
  • elasticsearch-tutorials是个父工程,里面有多个module,本篇实战的module是basic-crud,如下图红框
    java与es8实战之四:SpringBoot应用中操作es8(无安全检查)

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发表评论

评论已关闭。

相关文章