详细介绍:SpringBoot集成Elasticsearch | Spring官方场景启动器(Spring Data Elasticsearch)方式

SpringBoot集成Elasticsearch的三种核心方式,
Spring官方场景启动器
Elasticsearch 7.x专属HLRC(High Level Rest Client)
Elasticsearch 8.x专属Java Client

前言

Spring官方场景启动器(Spring Data Elasticsearch)

Spring Data Elasticsearch是Spring对ES官方接口的二次封装,优势是集成Spring生态更便捷,缺点是版本更新滞后

1. 版本匹配与Maven依赖

<dependencies>
  <!-- Spring Data Elasticsearch核心依赖 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    <!-- Web依赖(用于测试接口) -->
      <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>
        <!-- FastJSON(JSON序列化,可选) -->
          <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.83</version>
          </dependency>
        </dependencies>

2. 配置文件(application.yml)

支持ES集群配置,7.x默认未开启安全认证,8.x需额外配置账号密码与SSL(此处以7.x为例)。

server:
port: 8081 # 服务端口
spring:
elasticsearch:
rest:
# ES服务器地址(集群用逗号分隔,如127.0.0.1:9200,127.0.0.1:9201)
uris: http://127.0.0.1:9200
# 若开启安全认证(如8.x默认开启),需添加以下配置
# username: elastic
# password: 你的ES密码
# 连接超时配置
connection-timeout: 1000ms
socket-timeout: 30000ms

3. 核心代码实现

3.1 实体类(映射ES索引)

@Document指定索引名,@Id指定文档唯一标识,@Field指定字段类型与分词器。

环境提示

  • 开发/测试环境:可省略@Field注解部分配置,依赖ES动态映射快速验证功能;
  • 生产环境:必须通过@Field精准定义字段类型、分词器等(如jobNo设为Keyword、name指定IK分词器),避免动态映射导致的类型混乱或检索异常。
package com.es.demo.entity;
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;
import java.math.BigDecimal;
import java.util.Date;
/**
* 员工实体(映射ES索引:employee_spring_data)
*/
@Data
@Document(indexName = "employee_spring_data", shards = 3, replicas = 1)
// indexName:索引名;shards:分片数;replicas:副本数(生产环境根据集群调整)
public class EmployeeSpringData {
@Id // 对应ES文档的_id字段(唯一标识)
private String docId; // 文档ID(可自定义,也可让ES自动生成)
@Field(type = FieldType.Keyword) // Keyword:精确匹配,不分词
private String jobNo; // 工号(唯一,精确查询)
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
// Text:分词匹配;analyzer:索引时分词器;searchAnalyzer:查询时分词器(需提前安装IK分词器)
private String name; // 姓名(支持模糊查询)
@Field(type = FieldType.Keyword)
private String job; // 岗位(如Java开发)
@Field(type = FieldType.Integer)
private Integer age; // 年龄
@Field(type = FieldType.Double)
private BigDecimal salary; // 薪资
@Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd")
private Date jobDay; // 入职时间(自定义日期格式)
@Field(type = FieldType.Text, analyzer = "ik_smart")
private String remark; // 备注
}

3.2 Repository接口(CRUD基础操作)

继承ElasticsearchRepository,Spring会自动实现基础CRUD方法,无需手动编写。

package com.es.demo.repository;
import com.es.demo.entity.EmployeeSpringData;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 员工ES Repository(Spring Data自动实现CRUD)
* 泛型:<实体类, 文档ID类型>
  */
  @Repository
  public interface EmployeeSpringDataRepository extends ElasticsearchRepository<EmployeeSpringData, String> {
    // 1. 自定义查询:根据姓名模糊查询(Spring Data按方法名自动生成SQL)
    // 方法名规则:findBy + 字段名 + 查询规则(Containing=模糊匹配)
    List<EmployeeSpringData> findByNameContaining(String name);
      // 2. 自定义查询:根据岗位和年龄范围查询
      List<EmployeeSpringData> findByJobAndAgeBetween(String job, Integer minAge, Integer maxAge);
        }

3.3 Service层(业务逻辑封装)

整合Repository,处理复杂查询(如高亮、分页)。

package com.es.demo.service;
import com.es.demo.entity.EmployeeSpringData;
import com.es.demo.repository.EmployeeSpringDataRepository;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.domain.Page;
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.SearchHit;
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.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor // Lombok自动注入构造器(替代@Autowired)
public class EmployeeSpringDataService {
// 注入Repository(基础CRUD)
private final EmployeeSpringDataRepository employeeRepository;
// 注入Template(复杂查询,如高亮、聚合)
private final ElasticsearchRestTemplate elasticsearchTemplate;
/**
* 1. 添加/修改文档(docId存在则修改,不存在则新增)
*/
public EmployeeSpringData save(EmployeeSpringData employee) {
return employeeRepository.save(employee);
}
/**
* 2. 批量添加文档
*/
public List<EmployeeSpringData> batchSave(List<EmployeeSpringData> employees) {
  return (List<EmployeeSpringData>) employeeRepository.saveAll(employees);
    }
    /**
    * 3. 根据docId删除文档
    */
    public void deleteByDocId(String docId) {
    employeeRepository.deleteById(docId);
    }
    /**
    * 4. 根据docId查询文档
    */
    public EmployeeSpringData getByDocId(String docId) {
    // findById返回Optional,用orElse(null)处理不存在的情况
    return employeeRepository.findById(docId).orElse(null);
    }
    /**
    * 5. 高亮查询(姓名模糊匹配,分页)
    */
    public Page<EmployeeSpringData> searchHighlight(String name, Integer pageNum, Integer pageSize) {
      // 1. 构建高亮配置(红色span标签)
      HighlightBuilder.Field highlightField = new HighlightBuilder.Field("name")
      .preTags("<span style='color:red'>")
      .postTags("</span>")
      .requireFieldMatch(false); // 允许高亮多个字段
      // 2. 构建原生查询(NativeSearchQuery支持ES原生DSL)
      NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
      .withQuery(QueryBuilders.matchQuery("name", name)) // 姓名模糊匹配
      .withHighlightFields(highlightField) // 加入高亮配置
      .withPageable(PageRequest.of(pageNum - 1, pageSize)) // 分页(pageNum从0开始,需减1)
      .build();
      // 3. 执行查询并处理高亮结果
      SearchHits<EmployeeSpringData> searchHits = elasticsearchTemplate.search(searchQuery, EmployeeSpringData.class);
        // 转换为Page(符合Spring Data分页规范)
        List<EmployeeSpringData> content = searchHits.stream()
          .map(hit -> {
          EmployeeSpringData employee = hit.getContent();
          // 替换高亮字段(将原始name替换为高亮后的内容)
          if (!hit.getHighlightFields().isEmpty()) {
          String highlightName = hit.getHighlightFields().get("name").get(0);
          employee.setName(highlightName);
          }
          return employee;
          })
          .collect(Collectors.toList());
          // 构建Page对象(包含总条数、分页信息)
          long total = searchHits.getTotalHits();
          Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
          return new org.springframework.data.domain.PageImpl<>(content, pageable, total);
            }
            }

3.4 Controller层(测试接口)

package com.es.demo.controller;
import com.es.demo.entity.EmployeeSpringData;
import com.es.demo.service.EmployeeSpringDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/api/spring-data/employee")
@RequiredArgsConstructor
public class EmployeeSpringDataController {
private final EmployeeSpringDataService employeeService;
/**
* 1. 添加/修改员工
*/
@PostMapping("/save")
public EmployeeSpringData save(@RequestBody EmployeeSpringData employee) {
return employeeService.save(employee);
}
/**
* 2. 批量添加员工
*/
@PostMapping("/batch-save")
public List<EmployeeSpringData> batchSave(@RequestBody List<EmployeeSpringData> employees) {
  return employeeService.batchSave(employees);
  }
  /**
  * 3. 根据docId删除员工
  */
  @DeleteMapping("/delete/{docId}")
  public String delete(@PathVariable String docId) {
  employeeService.deleteByDocId(docId);
  return "删除成功(docId:" + docId + ")";
  }
  /**
  * 4. 根据docId查询员工
  */
  @GetMapping("/get/{docId}")
  public EmployeeSpringData get(@PathVariable String docId) {
  return employeeService.getByDocId(docId);
  }
  /**
  * 5. 高亮查询员工(分页)
  */
  @GetMapping("/search-highlight")
  public Page<EmployeeSpringData> searchHighlight(
    @RequestParam String name,
    @RequestParam(defaultValue = "1") Integer pageNum,
    @RequestParam(defaultValue = "10") Integer pageSize) {
    return employeeService.searchHighlight(name, pageNum, pageSize);
    }
    /**
    * 6. 测试示例:添加单个员工(方便手动测试,无需传JSON)
    */
    @GetMapping("/test/save")
    public EmployeeSpringData testSave(
    @RequestParam String jobNo,
    @RequestParam String name,
    @RequestParam String job,
    @RequestParam Integer age,
    @RequestParam BigDecimal salary,
    @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date jobDay,
    @RequestParam(required = false) String remark) {
    EmployeeSpringData employee = new EmployeeSpringData();
    employee.setJobNo(jobNo);
    employee.setName(name);
    employee.setJob(job);
    employee.setAge(age);
    employee.setSalary(salary);
    employee.setJobDay(jobDay);
    employee.setRemark(remark);
    // docId留空,让ES自动生成
    return employeeService.save(employee);
    }
    }

4. 测试步骤

  1. 启动ES服务器(版本7.15.2,确保9200端口可访问);
  2. 启动SpringBoot项目;
  3. 调用测试接口添加数据:访问http://localhost:8081/api/spring-data/employee/test/save?jobNo=2024001&name=张三&job=Java开发&age=28&salary=25000&jobDay=2023-01-15&remark=技术骨干
  4. 调用高亮查询接口:访问http://localhost:8081/api/spring-data/employee/search-highlight?name=张&pageNum=1&pageSize=10,返回结果中name字段会被红色span标签包裹。

posted @ 2025-12-12 12:29  clnchanpin  阅读(120)  评论(0)    收藏  举报