Springboot項目集成Spring Data elasticsearch


說明

  1. springboot版本為2.5.0
  2. jdk版本為1.8
  3. 本人在項目中集成了swagger2

參考了一個B站上的視頻:https://www.bilibili.com/video/BV13v41177Fu

本人把項目放到了gitee上:https://gitee.com/guoanhao/aoh-eslog.git

 

核心依賴

 <!-- spring data elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

本人的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>

    <groupId>org.example</groupId>
    <artifactId>aoh-eslog</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- spring data elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

        <!-- swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- swagger2換膚 -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>
        

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
View Code

application.yml

在yml文件中配置elasticsearchip和端口號(集群的話用逗號分割就可以了)

server:
  port: 8080
#  servlet:
#    context-path: /com/gah/service

spring:
  elasticsearch:
    rest:
      uris: http://192.168.186.142:9200
#      uris: http://192.168.186.142:9200,http://192.168.186.142:9200,http://192.168.186.142:9200


# 隊列實體類路徑配置,以便通過java反射來獲取實體類
pojo.path: com.nsccjn.aoh.eslog.pojo.

 

本人的實體類,測試類

package com.nsccjn.aoh.eslog.pojo;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 測試
 */
@Data
@Document(indexName = "test",createIndex = false)
public class Text {

    @Id
    private Integer id;
    @Field(type = FieldType.Text)
    private String name;
    @Field(type = FieldType.Integer)
    private Integer age;

    public Text() {

    }
    public Text(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

下面這個的實體類叫做Index(對應的elasticsearch的索引名稱是test)

測試類中使用的是這個實體類

由於索引名和實體類名稱不對應,所以下面的controller中沒法通過前台傳參的方式獲取並與elasticsearch的索引相對應(可以用Text實體類傳參)

package com.nsccjn.aoh.eslog.pojo;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 測試
 */
@Data
@Document(indexName = "test",createIndex = false)
public class Index {

    @Id
    private Integer id;
    @Field(type = FieldType.Text)
    private String name;
    @Field(type = FieldType.Integer)
    private Integer age;

    public Index() {

    }
    public Index(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

 

 

下面是測試類

import com.nsccjn.aoh.eslog.Application;
import com.nsccjn.aoh.eslog.dao.IndexRepository;
import com.nsccjn.aoh.eslog.dao.JobsRepository;
import com.nsccjn.aoh.eslog.pojo.Index;
import com.nsccjn.aoh.eslog.pojo.Jobs;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest(classes = Application.class)
public class ESLogTest {

    @Autowired
    private ElasticsearchRestTemplate template;
    @Autowired
    private JobsRepository jobsRepository;
    @Autowired
    private IndexRepository indexRepository;

    @Value("${pojo.path}")
    String POJO_PATH;

    /**
     * 新增索引
     */
    @Test
    public void testIndex() {

        // 獲取索引對象
        IndexOperations indexOperations = template.indexOps(Test.class);
        // 創建索引
        indexOperations.create();
        // 獲取映射
        Document mapping = indexOperations.createMapping(Test.class);
        // 將映射放入索引
        indexOperations.putMapping(mapping);
        // 判斷映射是否存在
        boolean exists = indexOperations.exists();
        System.out.printf(String.valueOf(exists));
        // Map<String, Object> mapping = indexOperations.getMapping();


        // System.out.printf(String.valueOf(mapping));

    }

    @Test
    public void testRepository() {
        // 添加
        // List<Index> list = new ArrayList<>();
        // list.add(new Index(10, "李清照", 26));
        // list.add(new Index(11, "辛稼軒", 20));
        // indexRepository.saveAll(list);

        // indexRepository.deleteAll();
        // 根據名稱查詢歷史名人
        // List<Index> indexList = indexRepository.findByName("%李%");
        // System.out.printf(String.valueOf(indexList));
        
        // 自定義規則查詢
        Index index = indexRepository.findByIdValue(10);
        System.out.printf(String.valueOf(index));

    }

    /**
     * 增刪改
     */
    @Test
    public void testCUD() {
        // 添加(id存在則更新)
        List<Index> list = new ArrayList<>();
        list.add(new Index(12, "蘇子瞻", 26));
        list.add(new Index(13, "王陽明", 20));
        // template.save(list);

        // 刪除test索引中id為11的數據
        template.delete("11", IndexCoordinates.of("test"));


    }

    /**
     * 查詢
     */
    @Test
    public void testSearch() {

        String startTime = "2021-07-20T14:20:00.000Z";
        String endTime = "2021-07-21T17:14:43.000Z";

        // 分頁
        Pageable pageable = PageRequest.of(0, 10);

        // 查詢字段是name值是’李清照‘的數據
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.boolQuery()
                        .must(QueryBuilders.matchQuery("jobname","大家好"))
                        .must(QueryBuilders.rangeQuery("@timestamp").gte(startTime).lte(endTime))
                )
                .withSort(SortBuilders.fieldSort("@timestamp").order(SortOrder.ASC))
                .withPageable(pageable)
                .build();

        // path = "com.nsccjn.aoh.eslog.pojo.Jobs";
        POJO_PATH += "JobsTime";
        Class clazz = null;
        try {
            clazz = Class.forName(POJO_PATH);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 指定要查詢的實體類
        // SearchHits<Jobs> search = template.search(query, Jobs.class);
        SearchHits<Jobs> search = template.search(query, clazz);

        System.out.println(search.getTotalHits());
        search.getSearchHits().forEach(System.out::println);
    }

    /**
     * 測試將查詢條件拿出來定義
     */
    @Test
    public void testSearch2() {

        String startTime = "2021-07-18T16:07:00.000Z";
        String endTime = "2021-07-21T17:07:00.000Z";

        Pageable pageable = PageRequest.of(0, 3);

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // queryBuilder.must(QueryBuilders.matchQuery("jobName", "大家好"));
        queryBuilder.must(QueryBuilders.rangeQuery("@timestamp").gte(startTime).lte(endTime));

        // 查詢字段是name值是’李清照‘的數據
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.boolQuery().must(queryBuilder))
                .withSort(SortBuilders.fieldSort("@timestamp").order(SortOrder.ASC))
                .withPageable(pageable)
                .build();

        NativeSearchQueryBuilder query2 = new NativeSearchQueryBuilder();
        // .withQuery(QueryBuilders.boolQuery().must(queryBuilder))
        // .withSort(SortBuilders.fieldSort("@timestamp").order(SortOrder.ASC))
        query2.withQuery(queryBuilder);
        query2.withPageable(pageable);

        new NativeSearchQueryBuilder();

        // NativeSearchQuery query = new NativeSearchQueryBuilder()
        //         .withQuery(QueryBuilders.boolQuery()
        //                 .must(QueryBuilders.matchQuery("jobname", "大家好"))
        //                 .must(QueryBuilders.rangeQuery("@timestamp").gte(startTime).lte(endTime)))
        //         // .withSort(SortBuilders.fieldSort("@timestamp").order(SortOrder.ASC))
        //         // .withPageable(pageable)
        //         .build();

        // 指定要查詢的實體類
        SearchHits<Jobs> search = template.search(query2.build(), Jobs.class);

        System.out.println(search.getTotalHits());

        search.getSearchHits().forEach(System.out::println);
    }

    /**
     * 測試反射獲取實體類
     * @throws ClassNotFoundException
     */
    @Test
    public void test() throws ClassNotFoundException {
        String path = "com.nsccjn.aoh.eslog.pojo.Jobs";
        Class clazz = Class.forName(path);

        // 獲取類名
        // String strName01 = clazz.getName();// 獲取完整類名com.sg.myReflection.bean.User
        // String strName02 = clazz.getSimpleName();// 直接獲取類名 User
        // System.out.printf(strName01);


        // System.out.println(c2);

    }

}
View Code

 

Chrome瀏覽器有一個elasticsearch的插件,如下

 

 

 

 

到此基本就結束了,不過本人又修改了一下部分代碼(在controller中改的)

通過java反射的方式獲取實體類,就可以在前台傳相應的index(對應實體類名稱)然后后返回相應的結果

package com.nsccjn.aoh.eslog.controller;

import com.nsccjn.aoh.eslog.pojo.Jobs;
import io.netty.util.internal.StringUtil;
import io.swagger.annotations.*;
import lombok.SneakyThrows;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Api(value = "ESlog接口", tags = {"獲取ESlog信息接口"})
@RestController
public class ESLogController {

    @Autowired
    private ElasticsearchRestTemplate template;

    @Value("${pojo.path}")
    String POJO_PATH;

    @GetMapping("/hel")
    public String hello() {
        return "李清照";
    }

    /**
     * 獲取elasticsearch中的日志
     *
     * @param startTime 開始時間
     * @param endTime   結束時間
     * @param queue     隊列
     * @param key       關鍵字
     * @param fieldName 關鍵字對應的要查詢的字段
     * @param page      當前頁
     * @param size      一頁顯示多少條數據
     */
    @ApiOperation(value = "查詢ESlog信息", notes = "查詢ESlog信息", httpMethod = "GET", produces = "multipart/form-data")
    @GetMapping("/queryESlog")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "startTime", value = "開始時間", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "endTime", value = "結束時間", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "queue", value = "隊列名稱", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "key", value = "關鍵字", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "fieldName", value = "要查詢的字段名稱", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "當前頁", dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "size", value = "一頁顯示多少條數據", dataType = "Integer", paramType = "query")
    })
    public Object queryESlog(String startTime,
                             String endTime,
                             String queue,
                             String key,
                             String fieldName,
                             Integer page,
                             Integer size) {

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 查詢字段是fieldName,值是’key‘的數據
        if (!StringUtil.isNullOrEmpty(key) && !StringUtil.isNullOrEmpty(fieldName)) {
            queryBuilder.must(QueryBuilders.matchQuery(fieldName, key));
        }
        // 時間范圍查詢
        if (!StringUtil.isNullOrEmpty(startTime) && !StringUtil.isNullOrEmpty(endTime)) {
            queryBuilder.must(QueryBuilders.rangeQuery("@timestamp").gte(startTime).lte(endTime));
        }

        // 創建NativeSearchQueryBuilder
        NativeSearchQueryBuilder query = new NativeSearchQueryBuilder();
        query.withQuery(queryBuilder);
        // 分頁查詢
        if (page != null && size != null) {
            Pageable pageable = PageRequest.of(page, size);
            query.withPageable(pageable);
        }
        // 默認按照時間倒序排序
        // query.withSort(SortBuilders.fieldSort("@timestamp").order(SortOrder.DESC));
        query.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));

        try {
            // 通過反射的方式獲取類對象
            Class clazz = Class.forName(POJO_PATH + queue);
            // 查詢
            SearchHits<Jobs> search = template.search(query.build(), clazz);
            // search.getSearchHits().forEach(System.out::println);
            return search;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }


}
View Code

 

本人集成了swagger2,相應的代碼如下,依賴在上面給出了,swagger2配置類如下

package com.nsccjn.aoh.eslog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * swagger2配置文件
 * http://localhost:8088/swagger-ui.html    原路徑
 * http://localhost:8088/doc.html    換膚之后的路徑
 */
@Configuration
@EnableSwagger2
public class Swagger2 {


    //api接口包掃描路徑
    public static final String SWAGGER_SCAN_BASE_PACKAGE = "com.nsccjn.aoh.eslog.controller";

    public static final String VERSION = "1.0.0";

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)   // 指定API類型為SWAGGER_2
                .apiInfo(apiInfo())                      // 定義API文檔匯總信息
                .select()
                .apis(RequestHandlerSelectors
                        .basePackage(SWAGGER_SCAN_BASE_PACKAGE))   // 指定controller包,用於生成api的controller包
                .paths(PathSelectors.any())              // 可以根據url路徑設置哪些請求加入文檔,忽略哪些請求
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("ESLog服務平台") //設置文檔的標題
                .contact(new Contact("易算平台",
                        "http://localhost:8080/hel",
                        ""))
                .description("ESLog服務平台 API 接口文檔") // 設置文檔的描述
                .version(VERSION) // 設置文檔的版本信息-> 1.0.0 Version information
                .termsOfServiceUrl("http://www.baidu.com") // 設置文檔的License信息->1.3 License information
                .build();
    }
}
View Code

經過測試@ApiParam注解不好用,於是就換成了@ApiImplicitParams和@ApiImplicitParam。使用@ApiParam時前台傳的值不能為空,為空就報錯。

我們使用了swagger2換膚,路徑如下

http://localhost:8080/swagger-ui.html    原路徑
http://localhost:8080/doc.html    換膚之后的路徑

 

 調試頁面

 

 

 查詢結果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM