1. 测试Api连接
1.2. 添加依赖
<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>x-pack-sql-jdbc</artifactId>
<version>8.11.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
</dependency>
-->
</dependencies>
1.3. 工具类
package io.os.es.kit;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
public class ElasticClient {
//同步需关闭传输对象:transport.close();
private ElasticsearchClient syncClient;
private ElasticsearchTransport transport;
private ElasticsearchAsyncClient asyncClient;
public ElasticsearchClient getSyncClient() {
return syncClient;
}
public void setSyncClient(ElasticsearchClient syncClient) {
this.syncClient = syncClient;
}
public ElasticsearchTransport getTransport() {
return transport;
}
public void setTransport(ElasticsearchTransport transport) {
this.transport = transport;
}
public ElasticsearchAsyncClient getAsyncClient() {
return asyncClient;
}
public void setAsyncClient(ElasticsearchAsyncClient asyncClient) {
this.asyncClient = asyncClient;
}
//syncClient操作完需关闭transport,而asyncClient则无需
void connectToElastic(String userName,String cipherCode,String certificatePath,HttpHost httpHost) {
try {
final CredentialsProvider provider = new BasicCredentialsProvider();
Credentials credential = new UsernamePasswordCredentials(userName,cipherCode);
provider.setCredentials(AuthScope.ANY,credential);
Path caPath = Path.of(certificatePath);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
Certificate trustCa;
try(InputStream is = Files.newInputStream(caPath)){
trustCa = factory.generateCertificate(is);
}
KeyStore trustStore = KeyStore.getInstance("pkcs12");
trustStore.load(null,null);
trustStore.setCertificateEntry("ca",trustCa);
SSLContextBuilder sslContextBuilder = SSLContexts.custom()
.loadTrustMaterial(trustStore,null);
final SSLContext sslContext = sslContextBuilder.build();
RestClientBuilder builder = RestClient
.builder(new HttpHost(httpHost.getHostName(),httpHost.getPort(),httpHost.getSchemeName()))
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder asyncBuilder) {
return asyncBuilder.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setDefaultCredentialsProvider(provider);
}
});
RestClient restClient = builder.build();
transport = new RestClientTransport(restClient,new JacksonJsonpMapper());
syncClient = new ElasticsearchClient(transport);
asyncClient = new ElasticsearchAsyncClient(transport);
} catch (IOException | CertificateException | KeyStoreException
| NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
}
}
1.4. 测试代码
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import org.apache.http.HttpHost;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.transport.endpoints.BooleanResponse;
public class Tester {
private static final Logger logger = LoggerFactory
.getLogger(MethodHandles.lookup().lookupClass());
public static void main(String[] sa) throws ElasticsearchException, IOException{
ElasticClient client = new ElasticClient();
String userName = "elastic";
String cipherCode = "es8es8";
String certificatePath = "src/main/resources/certificate/http_ca.crt";
HttpHost httpHost = new HttpHost("192.168.0.123",9200,"https");
client.connectToElastic(userName,cipherCode,certificatePath,httpHost);
BooleanResponse response = client.getSyncClient().indices().exists(r -> r.index("elf"));
logger.error("exist index:{}",response.value());
client.getTransport().close();
}
}
-
21:15:17.754 [main] ERROR io.os.es.kit.Tester - exist index:true
-
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties
2. Spring Data整合ES8
-
ElasticSearch 8.11.2
-
Spring Data 2023.1
-
Spring Data ElasticSearch 5.2.0
-
Spring Boot 3.2.0
2.1. Project Structure
📄 pom.xml
📂 src
📂 main
📂 java
📂 io.os.es
📄 ElasticEntry.java
📂 config
📄 ElasticConfig.java
📂 controller
📄 ElasticController.java
📂 resources
📄 application.yaml
📂 certificate
📄 http_ca.crt
2.2. Dependency
<dependencies>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.yaml</include>
</includes>
</resource>
</resources>
</build>
2.3. application.yaml
spring:
elasticsearch:
username: elastic
password: es8es8
restclient:
ssl:
bundle: src/main/resources/certificate/http_ca.crt
#此处不能携带schema,如https://192.168.0.123:9200
uris:
- 192.168.0.123:9200
data:
elasticsearch:
repositories:
enabled: true
2.4. Configuration
package io.os.es.config;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.time.Duration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
@Configuration
@EnableConfigurationProperties({ElasticsearchProperties.class})
public class ElasticConfig extends ElasticsearchConfiguration {
@Autowired
private ElasticsearchProperties prop;
@Override
public ClientConfiguration clientConfiguration() {
String[] uriArr = prop.getUris().toArray(String[]::new);
return ClientConfiguration.builder()
.connectedTo(uriArr)
.usingSsl(getSslContext(),(hostname,session) -> true)
.withConnectTimeout(Duration.ofSeconds(5))
.withSocketTimeout(Duration.ofSeconds(30))
.withBasicAuth(prop.getUsername(),prop.getPassword())
.build();
}
private SSLContext getSslContext(){
try {
Path caPath = Path.of(prop.getRestclient().getSsl().getBundle());
CertificateFactory factory = CertificateFactory.getInstance("X.509");
Certificate trustCa;
try(InputStream is = Files.newInputStream(caPath)){
trustCa = factory.generateCertificate(is);
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", trustCa);
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null,tmf.getTrustManagers(),null);
return context;
} catch (CertificateException | IOException | KeyStoreException
| NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
return null;
}
}
}
2.5. Controller
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
@RestController
@RequestMapping
public class ElasticController {
private static final Logger logger = LoggerFactory
.getLogger(MethodHandles.lookup().lookupClass());
@Autowired
private ElasticsearchClient esClient;
@GetMapping("/create")
public String createIndex() {
try {
String response = esClient.indices().create(r -> r.index(UUID.randomUUID().toString())).toString();
logger.error("create index:{}",response);
return response;
} catch (ElasticsearchException | IOException e) {
e.printStackTrace();
return null;
}
}
}
2.6. Entry
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ElasticEntry {
public static void main(String[] args) {
SpringApplication.run(ElasticEntry.class, args);
}
}
2023-12-10T11:02:54.544+08:00 ERROR 40672 i.o.e.c.ElasticController
create index:CreateIndexResponse:
{"index":"26726252-8571-416a-b47a-47a6dc2124b2","shards_acknowledged":true,"acknowledged":true}
3. Elastic Client
3.1. Imperative Client
@Configuration
public class ImperativeElasticConfig
extends ElasticsearchConfiguration {}
@Autowired
ElasticsearchOperations imperativeOperation;
@Autowired
ElasticsearchClient imperativeClient;
@Autowired
RestClient restClient;
@Autowired
JsonpMapper jsonpMapper;
3.2. Reactive Client
@Configuration
public class ReactiveElasticConfig
extends ReactiveElasticsearchConfiguration {}
@Autowired
ReactiveElasticsearchOperations reactiveOperation;
@Autowired
ReactiveElasticsearchClient reactiveClient;
@Autowired
RestClient restClient;
@Autowired
JsonpMapper jsonpMapper;
4. Api
-
ElasticsearchTemplate
-
ElasticsearchRepository
-
ElasticsearchOperations(Recommended)
-
IndexOperations
-
SearchOperations
-
DocumentOperations
-
5. Elastic Crud
5.1. Employee
@Document(indexName = "employee", createIndex = true)
public class Employee {
@Id
private String employeeId;
@Field(type = FieldType.Text, name = "name")
private String name;
@Field(type = FieldType.Long, name = "salary")
private long salary;
public Employee() {}
public String getEmployeeId() {
return employeeId;
}
public void setEmployeeId(String employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getSalary() {
return salary;
}
public void setSalary(long salary) {
this.salary = salary;
}
}
5.2. Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.os.elastic.model.Employee;
@RestController
@RequestMapping
public class EmployeeController {
@Autowired
private ElasticsearchOperations elasticOperation;
@PostMapping("/employee")
public ResponseEntity<Employee> insert(@RequestBody Employee employee){
var emp = elasticOperation.save(employee);
return ResponseEntity.ok(emp);
}
@DeleteMapping("/deleteById/{employeeId}")
public ResponseEntity<String> deleteById(
@PathVariable("employeeId") String employeeId){
String empId = elasticOperation.delete(employeeId,Employee.class);
return ResponseEntity.ok(empId);
}
@PutMapping("/updateById")
public ResponseEntity<Employee> updateById(
@RequestBody Employee employee){
Employee emp = elasticOperation.get(employee.getEmployeeId(),Employee.class);
emp.setName(employee.getName());
emp.setSalary(employee.getSalary());
elasticOperation.save(emp);
return ResponseEntity.ok(emp);
}
@GetMapping("/getById/{employeeId}")
public ResponseEntity<Employee> getById(
@PathVariable("employeeId") String employeeId){
Employee emp = elasticOperation.get(employeeId,Employee.class);
return ResponseEntity.ok(emp);
}
}