java與es8實戰之四:SpringBoot應用中操作es8(無安全檢查)

来源:https://www.cnblogs.com/bolingcavalry/archive/2023/08/29/17658358.html
-Advertisement-
Play Games

### 歡迎訪問我的GitHub > 這裡分類和彙總了欣宸的全部原創(含配套源碼):[https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) ### 本篇概覽 - 本篇是《java與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實戰》系列的所有代碼都以子工程的形式存放在父工程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的操作都符合預期
    在這裡插入圖片描述
  • 再用eshead觀察product002索引的情況,如下圖,三個分片,一個副本,與代碼中設置的一致
    在這裡插入圖片描述
  • 至此最簡單的連接和操作ES實戰已經完成,希望本篇能給您一些參考,助您順利完成基本操作

是不是線程安全的

源碼下載

名稱 鏈接 備註
項目主頁 https://github.com/zq2599/blog_demos 該項目在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該項目源碼的倉庫地址,https協議
git倉庫地址(ssh) [email protected]:zq2599/blog_demos.git 該項目源碼的倉庫地址,ssh協議
  • 這個git項目中有多個文件夾,本次實戰的源碼在elasticsearch-tutorials文件夾下,如下圖紅框
    在這裡插入圖片描述
  • elasticsearch-tutorials是個父工程,裡面有多個module,本篇實戰的module是basic-crud,如下圖紅框
    在這裡插入圖片描述

歡迎關註博客園:程式員欣宸

學習路上,你不孤單,欣宸原創一路相伴...


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Boost ASIO(Asynchronous I/O)是一個用於非同步I/O操作的C++庫,該框架提供了一種方便的方式來處理網路通信、多線程編程和非同步操作。特別適用於網路應用程式的開發,從基本的網路通信到複雜的非同步操作,如遠程式控制製程序、高併發伺服器等都可以使用該框架。該框架的優勢在於其允許處理多個並... ...
  • 在CMS之前的垃圾回收器,要麼就是串列垃圾回收方式,要麼就是關註系統吞吐量,而 CMS 垃圾回收器的出現,則打破了這個尷尬的局面。 ...
  • ## 指令重排序 ### 1、問題描述 首先一定要明確:指令重排序和有序性是不一樣的。這一點非常重要。 我們經常都會這麼說: - volatile能保證記憶體可見性、禁止指令重排序但是不能保證原子性。 - synchronized能保證原子性、可見性和有序性。 > 註意:這裡的有序性並不是代表能禁止指 ...
  • 本文分享自華為雲社區《哪些場景下Spring的事務會失效?》,作者:冰 河 。 在日常工作中,如果對Spring的事務管理功能使用不當,則會造成Spring事務不生效的問題。而針對Spring事務不生效的問題,也是在跳槽面試中被問的比較頻繁的一個問題。 今天,我們就一起梳理下有哪些場景會導致Spri ...
  • ### 前言 AC自動機($Aho\ Corasick\ Atomaton$)有著一種 [$KMP$](https://www.cnblogs.com/pdpdzaa/p/17641166.html) 的思想,所以在學習之前建議先學一下 $KMP$。同時還需要瞭解一下 $Trie$ 樹(建議去看一下 ...
  • `go embed` 是 Go 1.16 中引入的特性,它允許將文件嵌入到 Go 代碼中,以便在運行時訪問這些文件。這對於將靜態資源(如 HTML、CSS、JavaScript 文件)直接嵌入到 Go 二進位文件中,以及簡化文件分發和部署非常有用。下麵是關於 `go embed` 的詳細介紹: ** ...
  • ## 教程簡介 R是用於統計分析、繪圖的語言和操作環境。R是屬於GNU系統的一個自由、免費、源代碼開放的軟體,它是一個用於統計計算和統計製圖的優秀工具。R語言的核心是解釋電腦語言,其允許分支和迴圈以及使用函數的模塊化編程。 R語言允許與以C,C ++,.Net,Python或FORTRAN語言編寫 ...
  • 作者:TinyThing 鏈接:https://www.jianshu.com/p/b52db905f020 ## 0x0 背景 > 項目中使用LocalDateTime系列作為dto中時間的類型,但是spring收到參數後總報錯,為了全局配置時間類型轉換,嘗試瞭如下3中方法。 > > **註:本文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...