02|基于Springboot搭建Elasticsaerch Java Client环境

103 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

1.搭建环境

仅演示重点步骤,具体的代码可以在文后下载

所需准备

  • JDK:1.8以上
  • IDEA
  • SpringBoot:2.7.5

新建一个工程的过程不再详细赘述,直接新建一个springboot工程,然后在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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.7.5</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     
     <groupId>com.daiyu</groupId>
     <artifactId>elastic-learn</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <name>elastic-learn</name>
     <description>Demo project for Spring Boot</description>
     
     <properties>
         <java.version>11</java.version>
         <elastic.version>8.5.0</elastic.version>
         <jakarta.version>2.0.1</jakarta.version>
         <httpclient.version>4.5.13</httpclient.version>
         <pagehelper.version>5.2.1</pagehelper.version>
         <commons.version>3.12.0</commons.version>
         <guava.version>31.1-jre</guava.version>
         <collections4.verison>4.4</collections4.verison>
     </properties>
     
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 ​
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>co.elastic.clients</groupId>
             <artifactId>elasticsearch-java</artifactId>
             <version>${elastic.version}</version>
             <exclusions>
                 <exclusion>
                     <artifactId>jakarta.json-api</artifactId>
                     <groupId>jakarta.json</groupId>
                 </exclusion>
             </exclusions>
         </dependency>
         <dependency>
             <artifactId>jakarta.json-api</artifactId>
             <groupId>jakarta.json</groupId>
             <version>${jakarta.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
             <version>${httpclient.version}</version>
         </dependency>
         <dependency>
             <groupId>com.github.pagehelper</groupId>
             <artifactId>pagehelper</artifactId>
             <version>${pagehelper.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <version>${commons.version}</version>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <version>${guava.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-collections4</artifactId>
             <version>${collections4.verison}</version>
         </dependency>
 ​
     </dependencies>
 ​
     <build>
         <plugins>
             <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>
     </build>
 ​
 </project>
 ​

2.在application.yml填写相关配置

在项目的resources->application.yml填写配置

 server:
   port: 8089
 elastic:
   username: elastic    #访问es的用户名
   password: 123456     #访问es的密码
   hostname: localhost  #访问es的地址
   port: 9200           #访问es的端口
   schema: https        #ssl的方式访问es
 

3.下载安全证书

es的安全证书如何获取呢?这里有个简单的方法,我们打开浏览器在浏览器输入https://localhost:9200,会弹出如下界面。

因为我们要用https的方式访问es,所以我们需要配置安全证书,在项目的resources下创建cert文件夹,用来存放es的安全证书。

image-20221117104040663.png

我们点击地址栏的那个显示叹号的红色小三角,然后点击证书无效

image-20221117104336113.png

在弹出的界面,选择详情信息,然后点击最下边的导出,将文件进行保存,然后复制到Springboot项目下的resources->cert文件夹下

image-20221117104517522.png

复制后如下图所示

image-20221117104655853.png

4.新建包结构

项目的目录结构如下所示

image-20221117105721005.png

.
├── ElasticLearnApplication.java  #启动类
├── common                        #公共类
├── config                        #配置类
├── controller                    #用于跟web请求交互
├── domin                         #用于跟存放一些跟前后端交互的实体类
└── service                       #主要用于业务操作

5.编写es工具类,进行es链接

5.1 新建配置文件

在config包下新建ElasticConfig,主要是声明一些配置信息,文件具体内容如下

@Data
@Configuration
public class ElasticConfig {

    @Value("${elastic.hostname}")
    private String hostname;

    @Value("${elastic.port}")
    private int port;

    @Value("${elastic.username}")
    private String username;

    @Value("${elastic.password}")
    private String password;

    @Value("${elastic.schema}")
    private String schema;

}	

5.2 新建es工具类

这个工具类主要是用于es链接,初始化ElasticsearchClient,后期会在里边进行一些增删改查工具方法的封装。

​ 在common包新建util包,然后在util包下新建ElasticClient.java文件,这个文件期望被Spring进行管理,所以我们在这个类上加上**@Component**这个注解。

​ Elasticsearch8.X版本的java client已经不推荐使用High Level Client,所以本专栏全部使用的是官方推荐的ElasticsearchClient这个客户端工具。

详细文件代码如下

@Slf4j
public class ElasticsearchUtil {

     /**
     * 同步客户端
     *
     * @param elasticConfig
     * @return
     */
    public ElasticsearchClient elasticsearchClient(ElasticConfig elasticConfig) {
        ElasticsearchTransport transport = getElasticsearchTransport(elasticConfig);
        return new ElasticsearchClient(transport);
    }

    /**
     * 异步客户端
     *
     * @param elasticConfig
     * @return
     */
    public ElasticsearchAsyncClient elasticsearchAsyncClient(ElasticConfig elasticConfig) {
        ElasticsearchTransport transport = getElasticsearchTransport(elasticConfig);
        return new ElasticsearchAsyncClient(transport);
    }

    private ElasticsearchTransport getElasticsearchTransport(ElasticConfig elasticConfig) {
        //1.第一步,创建用户登陆信息的工厂类
      final CredentialsProvider credentialsProvider =
                new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(elasticConfig.getUsername(), elasticConfig.getPassword()));

       //2.第二步,创建证书文件的路径
        Path certPath = Paths.get("/Users/apple/IdeaProjects/myproject/elastic-learn/src/main/resources/cert/es01.cer");
       //配置HTTPS访问
        SSLContext sslContext = null;
        try {
          //3.第三步,返回实现指定证书类型的证书工厂对象
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            Certificate trustedCa;
            try (InputStream is = Files.newInputStream(certPath)) {
              //4.第四步,从Stream流中读取证书文件,生成证书对象
                trustedCa = factory.generateCertificate(is);
            }
          //5.第五步,返回指定类型的密钥库对象
            KeyStore trustStore = KeyStore.getInstance("pkcs12");
            trustStore.load(null, null);
            trustStore.setCertificateEntry("ca", trustedCa);
            SSLContextBuilder sslContextBuilder = SSLContexts.custom()
                    .loadTrustMaterial(trustStore, null);
          //6.第六步,构建安全协议内容
            sslContext = sslContextBuilder.build();
        } catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
            log.error("ES连接认证失败", e);
        }

        SSLContext finalSslContext = sslContext;
        RestClientBuilder builder = RestClient.builder(
                new HttpHost(elasticConfig.getHostname(), elasticConfig.getPort(), elasticConfig.getSchema()))
                .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                        .setSSLContext(finalSslContext)
                        .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                        .setDefaultCredentialsProvider(credentialsProvider));
        RestClient client = builder.build();
        return new RestClientTransport(client, new JacksonJsonpMapper());
    }
}

代码中涉及两个概念解释下:

  • X.509是一种数字证书格式标准。应用很广泛,现在HTTPS依赖的SSL证书使用的就是使用的X.509格式。这也就是说,每当我们打开https开头的网站都会用到它。

  • PKCS12是一种交换数字证书的加密标准,用来描述个人身份信息。如:用户公钥私钥、证书等。

接下来讲一下getElasticsearchTransport()方法这段代码的大致思路:

  • 第一步,首先创建一个维护用户登陆信息的工厂类,因为我们在实际生产过程中为了保证线程安全,此工厂类里面的内容是不能被修改的,所以我们要保证他的线程安全,用final进行修饰

     final CredentialsProvider credentialsProvider =  new BasicCredentialsProvider();
    
  • 第二步,接下来创建Path.get()方法获得文件的路径

  • 第三步,返回实现指定证书类型的证书工厂对象,我们通过CertificateFactory.getInstance()这个方法,传入X.509,返回X.509类型的证书工厂

  • 第四步,从从Stream流中读取证书文件,生成证书对象

  • 第五步,通过 KeyStore.getInstance()方法,返回指定类型的密钥库对象

  • 第六步,构建安全协议的实现sslContext

5.3编写ES工具类

此工具类,主要是封装我们日常经常使用的一些CURD方法。

在common->util下新建ElasticsearchUtil.java文件,我们先写一个简单的方法,查询索引是否存在的方法,大致代码如下:

@Component
@Slf4j
public class ElasticsearchUtil {
    //同步客户端
    private ElasticsearchClient client;
    //异步客户端
    private ElasticsearchAsyncClient asyncClient;


    public ElasticsearchUtil(ElasticConfig elasticConfig) {
        ElasticClient elasticClient=new ElasticClient();
        this.client = elasticClient.elasticsearchClient(elasticConfig);
        this.asyncClient = elasticClient.elasticsearchAsyncClient(elasticConfig);
    }

    /**
     * 判断索引是否存在
     *
     * @return
     * @throws Exception
     */
    public Boolean isExistsIndex(String indexName) {
        BooleanResponse exists = null;
        try {
            exists = client.indices().exists(o -> o.index(indexName));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return exists.value();
    }
}

5.4 测试工具类

接下来我们分别在controller、service包下创建IndexController.java、IndexService.java、IndexServiceImpl.java,详细代码如下:

  • IndexService.java
public interface IndexService {
    Boolean isExistsIndex();
}
  • IndexServiceImpl.java
@Service
public class IndexServiceImpl implements IndexService {
    private static final String index = "customer";

    @Resource
    private ElasticsearchUtil client;

    @Override
    public Boolean isExistsIndex() {
        Boolean existsIndex = client.isExistsIndex(index);
        return existsIndex;
    }
}
  • IndexController.java
@RequestMapping("/index")
@Controller
public class IndexController {
    @Resource
    private IndexService indexService;

    @GetMapping("/isExists")
    @ResponseBody
    private Boolean isExistsIndex() {
        return indexService.isExistsIndex();
    }
}

启动项目,然后通过postman等接口调用工具进行测试

image-20221117153124674.png

返回true,说明我们的客户端成功连接到elasticsearch。

在接下来我们就开始学习elasticsearch8的CURD简单操作,以及一些复杂场景的应用,并通过java客户端进行实现