本次Spring Boot集成ES,是基于前几篇文章的数据测试,因此在此不再细说,如有不懂的地方,可以先去查看ES前几篇文章介绍。
传送门:
ElasticSearch入门:https://ramona-chen.top/2020/02/29/elasticsearch-ru-men/
ElasticSearch基本用法:https://ramona-chen.top/2020/03/01/elasticsearch-ji-ben-yong-fa/
ElasticSearch高级查询:https://ramona-chen.top/2020/03/02/elasticsearch-gao-ji-cha-xun/
一、Springboot集成ElasticSearch
分布式ES配置调用方式核心代码:
package com.imooc.es.easticsearch;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Configuration
public class MyConfig {
@Bean
public TransportClient client() throws UnknownHostException {
// 此处对应你自己的cluster.name
Settings settings = Settings.builder().put("cluster.name", "cyh").build();
PreBuiltTransportClient client = new PreBuiltTransportClient(settings);
int[] local_ports = {9300,9301,9302};
for (int port : local_ports) {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"),port));
}
return client;
}
}
遇到的问题(运行报错):
org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available
原因:
Elasticsearch版本客户端与服务端版本不一致问题。
解决:
更改elasticsearch5.X调用方式。
错误代码:
for (int port : local_ports) {
client.addTransportAddress(new TransportAddress(
InetAddress.getByName("localhost"), port));
}
改正之后的代码:
for (int port : local_ports) {
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"),port));
}
参考:
二、接口开发
图书管理系统接口开发数据准备:
1、查询接口开发
// 查询接口
@GetMapping("/get/book/novel")
public ResponseEntity get(@RequestParam(name = "id", defaultValue = "") String id) {
if (id.isEmpty()) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
GetResponse response = client.prepareGet("book", "novel", id).get();
if (!response.isExists()) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
return new ResponseEntity(response.getSource(), HttpStatus.OK);
}
接口测试:
2、增加接口开发
// 增加接口
@PostMapping("/add/book/novel")
public ResponseEntity add(
@RequestParam(name = "title") String title,
@RequestParam(name = "author") String author,
@RequestParam(name = "word_count") int wordCount,
@RequestParam(name = "publish_date")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate) {
try {
XContentBuilder content = XContentFactory.jsonBuilder().startObject()
.field("title", title)
.field("author", author)
.field("word_count", wordCount)
.field("publish_date", publishDate.getTime())
.endObject();
IndexResponse response = client.prepareIndex("book", "novel")
.setSource(content)
.get();
return new ResponseEntity(response.getId(), HttpStatus.OK);
} catch (IOException e) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
接口测试:
遇到的问题:
使用Postman测试接口,可以看到在使用默认的form-data类型时出现了HTTP Status 400 - Required String parameter ‘xx’ is not present
这个错误(如下图),更换成x-www-form-urlencoded类型时返回成功。
如果使用@RequestBody接收参数,同@RequestParam一样,都是需要设置x-www-form-urlencoded类型才能正确返回。
原因:
@RequestBody这个一般处理的是在ajax请求中声明contentType: “application/json; charset=utf-8”时候。也就是json数据或者xml。
@RequestParam这个一般就是在ajax里面没有声明contentType的时候,为默认的urlencode格式时,用这个。
详细说明参考:
已是寒冬:https://blog.csdn.net/qq_26761587/article/details/73691189
3、删除接口开发
// 删除接口
@DeleteMapping("/delete/book/novel")
@ResponseBody
public ResponseEntity delete(@RequestParam(name = "id") String id) {
DeleteResponse response = client.prepareDelete("book", "novel", id).get();
return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);
}
接口测试:
4、更新接口开发
// 更新接口
@PutMapping("/update/book/novel")
@ResponseBody
public ResponseEntity update(
@RequestParam(name = "id") String id,
@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "author", required = false) String author,
@RequestParam(name = "word_count", required = false) Integer wordCount,
@RequestParam(name = "publish_date", required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate) {
try {
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
if (title != null) {
builder.field("title", title);
}
if (author != null) {
builder.field("author", author);
}
if (wordCount != null) {
builder.field("word_count", wordCount);
}
if (publishDate != null) {
builder.field("publish_date", publishDate.getTime());
}
builder.endObject();
UpdateRequest update = new UpdateRequest("book", "novel", id);
update.doc(builder);
UpdateResponse response = client.update(update).get();
return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
接口测试:
4、复合查询开发
// 复合查询
@PostMapping("query/book/novel")
@ResponseBody
public ResponseEntity query(
@RequestParam(name = "author", required = false) String author,
@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "gt_word_count", defaultValue = "0") int gtWordCount,
@RequestParam(name = "lt_word_count", required = false) Integer ltWordCount) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
if (author != null) {
boolQuery.must(QueryBuilders.matchQuery("author", author));
}
if (title != null) {
boolQuery.must(QueryBuilders.matchQuery("title", title));
}
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("word_count").from(gtWordCount);
if (ltWordCount != null && ltWordCount > 0) {
rangeQuery.to(ltWordCount);
}
boolQuery.filter(rangeQuery);
SearchRequestBuilder builder = client.prepareSearch("book").setTypes("novel")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuery)
.setFrom(0)
.setSize(10);
SearchResponse response = builder.get();
List result = new ArrayList<Map<String, Object>>();
for (SearchHit hit : response.getHits()) {
result.add(hit.getSourceAsMap());
}
return new ResponseEntity(result, HttpStatus.OK);
}
接口测试: