创建项目
使用SpringBoot初始化工具初始化一个SpringBoot的基础项目,并添加相关的依赖
<dependency><groupId>org.modelmapper</groupId><artifactId>modelmapper</artifactId><version>3.1.0</version></dependency><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-jpa</artifactId><version>5.0.0</version></dependency><!--JPA包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!--ElasticSearch包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></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>
修改SpringBoot的配置文件
server:port: 8888spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/xxxxx?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: xxxxxpassword: xxxxxhikari:connection-test-query: 'select 1'jpa:hibernate:ddl-auto: updatedatabase-platform: org.hibernate.dialect.MySQL5InnoDBDialectshow-sql: trueopen-in-view: falseelasticsearch:uris: http://localhost:9200connection-timeout: 10ssocket-timeout: 30slogging:file:name: ./log/out.loglevel:root: infoorg.springframework.data.elasticsearch.client.WIRE: trace
配置文件
使用@configuration注解标明ES的配置文件
package com.example.crontestjpa.config;import org.elasticsearch.client.RestHighLevelClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.elasticsearch.client.ClientConfiguration;import org.springframework.data.elasticsearch.client.RestClients;import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;import java.time.Duration;/*** Created By IntelliJ IDEA** @author IceCreamQAQ* @datetime 2022/11/19 星期六* Happy Every Coding Time~*/@Configurationpublic class ElasticSearchConfig extends AbstractElasticsearchConfiguration {@Bean@Overridepublic RestHighLevelClient elasticsearchClient() {ClientConfiguration configuration = ClientConfiguration.builder().connectedTo("127.0.0.1:9200").withConnectTimeout(Duration.ofSeconds(10))// 设置.withSocketTimeout(Duration.ofSeconds(30)).build();return RestClients.create(configuration).rest();}}
至此,已经完成了在SpringBoot中对ES的配置,之后可以对ES进行相关的操作
而经过了SpringData的整合之后,我们可以像操作数据库一般去实现对ElasticSearch的CRUD
没错,几乎同样的流程:定义实体 -> 创建实体对应的**repository** -> 使用**repository**完成相关的业务
操作ElasticSearch
将一些通用的属性封装成实体类,其他的实体类只需要继承此类便可拥有这些属性,而不用进行重复的操作
/*** Created By IntelliJ IDEA** @author IceCreamQAQ* @datetime 2022/11/20 星期日* Happy Every Coding Time~*/@MappedSuperclass@Data@AllArgsConstructor@NoArgsConstructor@EntityListeners(AuditingEntityListener.class)public class BaseModel implements Serializable {private static final long serialVersionUID = -8578918541296855061L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@CreatedDate@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)private LocalDateTime createTime;@LastModifiedDate@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)private LocalDateTime updateTime;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;BaseModel baseModel = (BaseModel) o;return id != null && Objects.equals(id, baseModel.id);}@Overridepublic int hashCode() {return getClass().hashCode();}}
/*** Created By IntelliJ IDEA** @author IceCreamQAQ* @datetime 2022/11/20 星期日* Happy Every Coding Time~*/@Data@AllArgsConstructor@NoArgsConstructor@Document(createIndex = false, indexName = "base")public class BaseESModel implements Serializable {private static final long serialVersionUID = 6681455862653089706L;@Id@Field(type = FieldType.Keyword)private String id;@CreatedDate@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING)@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)private LocalDateTime createTime;@LastModifiedDate@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8", shape = JsonFormat.Shape.STRING)@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = DateTimeFormat.ISO.DATE_TIME)@Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)private LocalDateTime updateTime;}
定义对象映射关系
这部分类似于对数据库操作时定义实体
定义ESBook类并继承于上述BaseESModel
/*** Created By IntelliJ IDEA** @author IceCreamQAQ* @datetime 2022/11/20 星期日* Happy Every Coding Time~*/@Document(indexName = "es_book")@Data@AllArgsConstructor@NoArgsConstructor@Builderpublic class ESBook extends BaseESModel {@Field(type = FieldType.Keyword)private String name;@Field(type = FieldType.Text, analyzer = "ik_max_word")private String author;@Field(type = FieldType.Text, analyzer = "ik_max_word")private String description;@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;ESBook esBook = (ESBook) o;return Objects.equals(name, esBook.name) && Objects.equals(author, esBook.author) && Objects.equals(description, esBook.description);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), name, author, description);}}
@Document:表明这是映射到ES中的DOC,其中的indexName属性用来表示此实体类对应的索引名称@Id:对应到ES中的唯一标识Id@Field:定义字段类型等信息
定义Repository
定义ESBookRepository接口并继承于ElasticsearchRepository<ESBook, String>
/*** Created By IntelliJ IDEA** @author IceCreamQAQ* @datetime 2022/11/20 星期日* Happy Every Coding Time~*/@Repositorypublic interface ESBookRepository extends ElasticsearchRepository<ESBook, Long> {}
而同JPA中操作一样,当你继承了这个接口之后,就拥有了一些基础的CRUD的操作能力:
还可以通过
@Query创建查询,使用@Highlight来定义关键字高亮
并且,同样支持定义方法的名称来进行自定义的查询操作,方法名支持的关键字如下:

:::success
✋ 在这里,为了简洁,省略了创建数据库实体和对应的repository的过程。但是需要注意以下几点:
- 定义ElasticSearch的对象映射关系使用的是
@Document注解,定义数据库实体使用的是@Entity - 定义两者的持久层接口时,继承的接口不同,一个继承的是
ElasticsearchRepository,另外一个继承的是JPARepository - 为了直观体现两者的不同,可以将其定义在不同的包下,如下所示:

 - 可以在 
SpringBoot启动类上使用注解配置两者的扫描包路径,如下所示:
::: 
定义Service
这里不再是单单创建ES的Service,而是实现一个小需求:在保存业务数据到数据库的时候,将数据保存一份到ES中,在保存到ES中时,我们模拟高并发下的延时情况,使用异步保存的方式


可以看到,我们保存到ES中的操作其实是在用户拿到返回结果之后,也就是我们的异步操作是有效的
但我们也可以在JPA提供的钩子函数中执行保存ES的操作,如下所示:
可以看到,我们在这个函数中是能拿到保存到数据库中的数据的,因此,也可以在这里进行异步保存到ES的操作。
自定义查询
正如上文提到的,我们可以通过设置方法名,来实现自定义查询,这是极其语义化的
但注意的是,我们使用findAll()方法,获取到的数据类型是Page<ESUser>,而不是List列表
