SpringBoot集成Elasticsearch | Spring官方场景启动器(Spring Data Elasticsearch)方式
SpringBoot集成Elasticsearch | Spring官方场景启动器(Spring Data Elasticsearch)方式
- 前言
- 1. 版本匹配与Maven依赖
- 2. 配置文件(application.yml)
- 3. 核心代码实现
- 3.1 实体类(映射ES索引)
- 3.2 Repository接口(CRUD基础操作)
- 3.3 Service层(业务逻辑封装)
- 3.4 Controller层(测试接口)
- 4. 测试步骤
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: 1000mssocket-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. 测试步骤
- 启动ES服务器(版本7.15.2,确保9200端口可访问);
- 启动SpringBoot项目;
- 调用测试接口添加数据:访问
http://localhost:8081/api/spring-data/employee/test/save?jobNo=2024001&name=张三&job=Java开发&age=28&salary=25000&jobDay=2023-01-15&remark=技术骨干; - 调用高亮查询接口:访问
http://localhost:8081/api/spring-data/employee/search-highlight?name=张&pageNum=1&pageSize=10,返回结果中name字段会被红色span标签包裹。
