说明
- springboot版本为2.5.0
- jdk版本为1.8
- 本人在项目中集成了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>
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); } }
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; } }
本人集成了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(); } }
经过测试@ApiParam注解不好用,于是就换成了@ApiImplicitParams和@ApiImplicitParam。使用@ApiParam时前台传的值不能为空,为空就报错。
我们使用了swagger2换肤,路径如下
http://localhost:8080/swagger-ui.html 原路径 http://localhost:8080/doc.html 换肤之后的路径
调试页面
查询结果