From d370c794e19abe34790da99727c8aab902bcbf97 Mon Sep 17 00:00:00 2001 From: "Yangkai.Shen" <237497819@qq.com> Date: Fri, 19 Jan 2018 15:42:57 +0800 Subject: [PATCH] =?UTF-8?q?spring=20boot=20=E9=9B=86=E6=88=90=20ElasticSea?= =?UTF-8?q?rch=EF=BC=8C=E9=87=87=E7=94=A8=E5=8E=9F=E7=94=9F=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=E9=9B=86=E6=88=90=20ES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- TODO.md | 1 + spring-boot-demo-elasticsearch/.gitignore | 24 ++ spring-boot-demo-elasticsearch/README.md | 280 ++++++++++++++++++ spring-boot-demo-elasticsearch/pom.xml | 44 +++ ...pringBootDemoElasticsearchApplication.java | 26 ++ .../config/ElasticSearchConfig.java | 46 +++ .../web/base/ApiResponse.java | 48 +++ .../web/base/Status.java | 29 ++ .../web/controller/PersonController.java | 194 ++++++++++++ .../src/main/resources/application.yml | 8 + ...BootDemoElasticsearchApplicationTests.java | 16 + spring-boot-demo-parent/pom.xml | 3 +- 13 files changed, 724 insertions(+), 3 deletions(-) create mode 100644 spring-boot-demo-elasticsearch/.gitignore create mode 100644 spring-boot-demo-elasticsearch/README.md create mode 100644 spring-boot-demo-elasticsearch/pom.xml create mode 100644 spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplication.java create mode 100644 spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/config/ElasticSearchConfig.java create mode 100644 spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/ApiResponse.java create mode 100644 spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/Status.java create mode 100644 spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/controller/PersonController.java create mode 100644 spring-boot-demo-elasticsearch/src/main/resources/application.yml create mode 100644 spring-boot-demo-elasticsearch/src/test/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplicationTests.java diff --git a/README.md b/README.md index e967f98..504ff7a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Spring Boot Demo -spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actuator(监控)、admin(可视化监控)、logback(日志)、aopLog(通过 AOP 记录 web 请求日志)、统一异常处理( json 级别和页面级别)、freemarker(模板引擎)、thymeleaf(模板引擎)、JPA(ORM 框架)、mybatis(ORM 框架)、redis-cache(缓存)、swagger(API 接口管理测试)、ureport2(中国式报表)、打包成 war 文件,后续会集成activemq,email,shiro,websocket,quartz,netty等模块。 +spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actuator(监控)、admin(可视化监控)、logback(日志)、aopLog(通过 AOP 记录 web 请求日志)、统一异常处理( json 级别和页面级别)、freemarker(模板引擎)、thymeleaf(模板引擎)、JPA(ORM 框架)、mybatis(ORM 框架)、redis-cache(缓存)、swagger(API 接口管理测试)、ureport2(中国式报表)、打包成 war 文件、集成 ElasticSearch(采用原生操作 ES 的方式),后续会集成activemq,email,shiro,websocket,quartz,netty等模块。 依赖的 Spring Boot 版本: @@ -58,8 +58,11 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu ../spring-boot-demo-orm-mybatis ../spring-boot-demo-cache-redis ../spring-boot-demo-swagger + ../spring-boot-demo-rabc-shiro-mybatis ../spring-boot-demo-ureport2 ../spring-boot-demo-war + ../spring-boot-demo-util + ../spring-boot-demo-elasticsearch @@ -122,7 +125,7 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu com.google.guava guava - 20.0 + 23.0 org.projectlombok @@ -161,6 +164,7 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu | [spring-boot-demo-swagger](./spring-boot-demo-swagger) | spring-boot 集成 [spring-boot-starter-swagger](https://github.com/SpringForAll/spring-boot-starter-swagger) (由大佬[翟永超](http://blog.didispace.com/)开源)用于统一管理、测试 API 接口 | | [spring-boot-demo-ureport2](./spring-boot-demo-ureport2) | spring-boot 集成 [ureport2](https://github.com/youseries/ureport) 实现自定义报表(ureport2可以轻松实现复杂的中国式报表,功能十分强大) | | [spring-boot-demo-war](./spring-boot-demo-war) | spring-boot 打成 war 包的配置 | +| [spring-boot-demo-elasticsearch](./spring-boot-demo-elasticsearch) | spring-boot 集成 ElasticSearch(采用原生操作 ES 的方式) | # 官方提供的 starter 介绍 diff --git a/TODO.md b/TODO.md index e946b36..f3e307a 100644 --- a/TODO.md +++ b/TODO.md @@ -39,6 +39,7 @@ - [ ] spring-boot-demo-async(Spring boot 实现异步调用) - [ ] spring-boot-demo-dubbo(集成 dubbo) - [x] ~~spring-boot-demo-war(打包成war包)~~ +- [x] ~~spring-boot-demo-elasticsearch(集成 ElasticSearch,使用原生操作 ES 的方式)~~ ### 备注 diff --git a/spring-boot-demo-elasticsearch/.gitignore b/spring-boot-demo-elasticsearch/.gitignore new file mode 100644 index 0000000..2af7cef --- /dev/null +++ b/spring-boot-demo-elasticsearch/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-boot-demo-elasticsearch/README.md b/spring-boot-demo-elasticsearch/README.md new file mode 100644 index 0000000..dac0f2d --- /dev/null +++ b/spring-boot-demo-elasticsearch/README.md @@ -0,0 +1,280 @@ +# spring-boot-demo-elasticsearch + +依赖 [spring-boot-demo-parent](../spring-boot-demo-parent) + +ElasticSearch 的 demo 我这里没有使用 spring-data-elasticsearch,我使用的是原生的方式 + +操作 ElasticSearch 由很多种方式: + +1. ES 官方提供的原生方式,**本例子使用这种方式**,这种方式的好处是高度自定义,并且可以使用最新的 ES 版本,缺点就是所有操作都得自己写。 +2. 使用 Spring 官方提供的 spring-data-elasticsearch,这里给出地址 https://projects.spring.io/spring-data-elasticsearch/ ,采用的方式类似 JPA,并且为 SpringBoot 提供了一个 `spring-boot-starter-data-elasticsearch`,优点是操作 ES 的方式采用了 JPA 的方式,都已经封装好了,缺点是版本得随着官方慢慢迭代,不能使用 ES 的最新特性。 + +### pom.xml + +```xml + + + 4.0.0 + + spring-boot-demo-elasticsearch + 0.0.1-SNAPSHOT + jar + + spring-boot-demo-elasticsearch + Demo project for Spring Boot + + + com.xkcoding + spring-boot-demo-parent + 0.0.1-SNAPSHOT + ../spring-boot-demo-parent/pom.xml + + + + + 6.1.1 + + + + + + org.elasticsearch.client + transport + ${elasticsearch.version} + + + + org.apache.logging.log4j + log4j-core + 2.7 + + + + + spring-boot-demo-elasticsearch + + + +``` + +### application.yml + +```yaml +server: + port: 8080 + context-path: /demo +elasticsearch: + host: 127.0.0.1 + port: 9300 + cluster: + name: xkcoding +``` + +ElasticSearchConfig.java + +```java +/** + *

+ * ES 的配置类 + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.config + * @description: ES 的配置类 + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午4:41 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@Configuration +public class ElasticSearchConfig { + @Value("${elasticsearch.host}") + private String host; + + @Value("${elasticsearch.port}") + private int port; + + @Value("${elasticsearch.cluster.name}") + private String clusterName; + + @Bean + public TransportClient esClient() throws UnknownHostException { + Settings settings = Settings.builder().put("cluster.name", this.clusterName).put("client.transport.sniff", true).build(); + + TransportAddress master = new TransportAddress(InetAddress.getByName(host), port); + TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(master); + return client; + } +} +``` + +PersonController.java + +```java +/** + *

+ * Person Controller + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.web.controller + * @description: Person Controller + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午5:06 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@RestController +@Slf4j +public class PersonController { + public static final String INDEX = "people"; + public static final String TYPE = "person"; + + @Autowired + private TransportClient esClient; + + /** + * 插入一条数据到 ES 中,id 由 ES 生成 + * + * @param name 名称 + * @param country 国籍 + * @param age 年龄 + * @param birthday 生日 + * @return 插入数据的主键 + */ + @PostMapping("/person") + public ApiResponse add(@RequestParam String name, @RequestParam String country, @RequestParam Integer age, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birthday) { + try { + XContentBuilder content = XContentFactory.jsonBuilder().startObject().field("name", name).field("country", country).field("age", age).field("birthday", birthday.getTime()).endObject(); + + IndexResponse response = esClient.prepareIndex(INDEX, TYPE).setSource(content).get(); + return ApiResponse.ofSuccess(response.getId()); + } catch (IOException e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + /** + * 根据 id 删除 ES 的一条记录 + * + * @param id ES 中的 id + * @return DELETED 代表删除 + */ + @DeleteMapping("/person/{id}") + public ApiResponse delete(@PathVariable String id) { + DeleteResponse response = esClient.prepareDelete(INDEX, TYPE, id).get(); + return ApiResponse.ofSuccess(response.getResult()); + } + + /** + * 根据主键,修改传递字段对应的值 + * + * @param id ES 中的 id + * @param name 姓名 + * @param country 国籍 + * @param age 年龄 + * @param birthday 生日 + * @return UPDATED 代表文档修改成功 + */ + @PutMapping("/person/{id}") + public ApiResponse update(@PathVariable String id, @RequestParam(value = "name", required = false) String name, @RequestParam(value = "country", required = false) String country, @RequestParam(value = "age", required = false) Integer age, @RequestParam(value = "birthday", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birthday) { + UpdateRequest request = new UpdateRequest(INDEX, TYPE, id); + try { + XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); + if (!Strings.isNullOrEmpty(name)) { + builder.field("name", name); + } + if (!Strings.isNullOrEmpty(country)) { + builder.field("country", country); + } + if (age != null && age > 0) { + builder.field("age", age); + } + if (birthday != null) { + builder.field("birthday", birthday.getTime()); + } + builder.endObject(); + request.doc(builder); + } catch (IOException e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + try { + UpdateResponse response = esClient.update(request).get(); + return ApiResponse.ofSuccess(response); + } catch (Exception e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + /** + * 简单查询 根据 id 查 ES 中的文档内容 + * + * @param id ES 中存储的 id + * @return 对应 id 的文档内容 + */ + @GetMapping("/person/{id}") + public ApiResponse get(@PathVariable String id) { + GetResponse response = esClient.prepareGet(INDEX, TYPE, id).get(); + if (!response.isExists() || response.isSourceEmpty()) { + return ApiResponse.ofStatus(Status.NOT_FOUND); + } + return ApiResponse.ofSuccess(response.getSource()); + } + + /** + * 复合查询,根据传进来的条件,查询具体内容 + * + * @param name 根据姓名匹配 + * @param country 根据国籍匹配 + * @param gtAge 大于年龄 + * @param ltAge 小于年龄 + * @return 满足条件的文档内容 + */ + @PostMapping("/person/query") + public ApiResponse query(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "country", required = false) String country, + @RequestParam(value = "gt_age", defaultValue = "0") int gtAge, + @RequestParam(value = "lt_age", required = false) Integer ltAge) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + + if (!Strings.isNullOrEmpty(name)) { + boolQueryBuilder.must(QueryBuilders.matchQuery("name", name)); + } + + if (!Strings.isNullOrEmpty(country)) { + boolQueryBuilder.must(QueryBuilders.matchQuery("country", country)); + } + + RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").from(gtAge); + + if (ltAge != null && ltAge > 0) { + rangeQueryBuilder.to(ltAge); + } + + boolQueryBuilder.filter(rangeQueryBuilder); + + SearchRequestBuilder searchRequestBuilder = esClient.prepareSearch(INDEX) + .setTypes(TYPE) + .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) + .setQuery(boolQueryBuilder) + .setFrom(0) + .setSize(20); + + log.info("【query】:{}", searchRequestBuilder); + + SearchResponse searchResponse = searchRequestBuilder.get(); + List> result = Lists.newArrayList(); + searchResponse.getHits().forEach(hit -> { + result.add(hit.getSourceAsMap()); + }); + + return ApiResponse.ofSuccess(result); + } + +} +``` + diff --git a/spring-boot-demo-elasticsearch/pom.xml b/spring-boot-demo-elasticsearch/pom.xml new file mode 100644 index 0000000..6e4938c --- /dev/null +++ b/spring-boot-demo-elasticsearch/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + spring-boot-demo-elasticsearch + 0.0.1-SNAPSHOT + jar + + spring-boot-demo-elasticsearch + Demo project for Spring Boot + + + com.xkcoding + spring-boot-demo-parent + 0.0.1-SNAPSHOT + ../spring-boot-demo-parent/pom.xml + + + + + 6.1.1 + + + + + + org.elasticsearch.client + transport + ${elasticsearch.version} + + + + org.apache.logging.log4j + log4j-core + 2.7 + + + + + spring-boot-demo-elasticsearch + + + \ No newline at end of file diff --git a/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplication.java b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplication.java new file mode 100644 index 0000000..1c4154b --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplication.java @@ -0,0 +1,26 @@ +package com.xkcoding.springbootdemoelasticsearch; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + *

+ * 应用启动类 + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.web.controller + * @description: 应用启动类 + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午5:06 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@SpringBootApplication +public class SpringBootDemoElasticsearchApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringBootDemoElasticsearchApplication.class, args); + } + +} diff --git a/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/config/ElasticSearchConfig.java b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/config/ElasticSearchConfig.java new file mode 100644 index 0000000..471fd07 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/config/ElasticSearchConfig.java @@ -0,0 +1,46 @@ +package com.xkcoding.springbootdemoelasticsearch.config; + +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.transport.client.PreBuiltTransportClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + *

+ * ES 的配置类 + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.config + * @description: ES 的配置类 + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午4:41 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@Configuration +public class ElasticSearchConfig { + @Value("${elasticsearch.host}") + private String host; + + @Value("${elasticsearch.port}") + private int port; + + @Value("${elasticsearch.cluster.name}") + private String clusterName; + + @Bean + public TransportClient esClient() throws UnknownHostException { + Settings settings = Settings.builder().put("cluster.name", this.clusterName).put("client.transport.sniff", true).build(); + + TransportAddress master = new TransportAddress(InetAddress.getByName(host), port); + TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(master); + return client; + } +} diff --git a/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/ApiResponse.java b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/ApiResponse.java new file mode 100644 index 0000000..6808aa9 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/ApiResponse.java @@ -0,0 +1,48 @@ +package com.xkcoding.springbootdemoelasticsearch.web.base; + +import lombok.Data; + +/** + *

+ * 统一接口返回类型 + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch + * @description: 统一接口返回类型 + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午5:34 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@Data +public class ApiResponse { + private int code; + private String message; + private Object data; + private boolean more; + + public ApiResponse(int code, String message, Object data) { + this.code = code; + this.message = message; + this.data = data; + } + + public ApiResponse() { + this.code = Status.SUCCESS.getCode(); + this.message = Status.SUCCESS.getMsg(); + } + + public static ApiResponse ofMessage(int code, String message) { + return new ApiResponse(code, message, null); + } + + public static ApiResponse ofSuccess(Object data) { + return new ApiResponse(Status.SUCCESS.getCode(), Status.SUCCESS.getMsg(), data); + } + + public static ApiResponse ofStatus(Status status) { + return new ApiResponse(status.getCode(), status.getMsg(), null); + } + +} \ No newline at end of file diff --git a/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/Status.java b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/Status.java new file mode 100644 index 0000000..0200643 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/base/Status.java @@ -0,0 +1,29 @@ +package com.xkcoding.springbootdemoelasticsearch.web.base; + +import lombok.Getter; + +/** + *

+ * 通用状态码 + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.web.base + * @description: 通用状态码 + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午5:35 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@Getter +public enum Status { + SUCCESS(200, "OK"), BAD_REQUEST(400, "Bad Request"), NOT_FOUND(404, "Not Found"), INTERNAL_SERVER_ERROR(500, "Unknown Internal Error"); + + private int code; + private String msg; + + Status(int code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/controller/PersonController.java b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/controller/PersonController.java new file mode 100644 index 0000000..b2aa508 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/java/com/xkcoding/springbootdemoelasticsearch/web/controller/PersonController.java @@ -0,0 +1,194 @@ +package com.xkcoding.springbootdemoelasticsearch.web.controller; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.xkcoding.springbootdemoelasticsearch.web.base.ApiResponse; +import com.xkcoding.springbootdemoelasticsearch.web.base.Status; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.action.delete.DeleteResponse; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.search.SearchRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.client.transport.TransportClient; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.RangeQueryBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + *

+ * Person Controller + *

+ * + * @package: com.xkcoding.springbootdemoelasticsearch.web.controller + * @description: Person Controller + * @author: yangkai.shen + * @date: Created in 2018/1/18 下午5:06 + * @copyright: Copyright (c) 2018 + * @version: 0.0.1 + * @modified: yangkai.shen + */ +@RestController +@Slf4j +public class PersonController { + public static final String INDEX = "people"; + public static final String TYPE = "person"; + + @Autowired + private TransportClient esClient; + + /** + * 插入一条数据到 ES 中,id 由 ES 生成 + * + * @param name 名称 + * @param country 国籍 + * @param age 年龄 + * @param birthday 生日 + * @return 插入数据的主键 + */ + @PostMapping("/person") + public ApiResponse add(@RequestParam String name, @RequestParam String country, @RequestParam Integer age, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birthday) { + try { + XContentBuilder content = XContentFactory.jsonBuilder().startObject().field("name", name).field("country", country).field("age", age).field("birthday", birthday.getTime()).endObject(); + + IndexResponse response = esClient.prepareIndex(INDEX, TYPE).setSource(content).get(); + return ApiResponse.ofSuccess(response.getId()); + } catch (IOException e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + /** + * 根据 id 删除 ES 的一条记录 + * + * @param id ES 中的 id + * @return DELETED 代表删除 + */ + @DeleteMapping("/person/{id}") + public ApiResponse delete(@PathVariable String id) { + DeleteResponse response = esClient.prepareDelete(INDEX, TYPE, id).get(); + return ApiResponse.ofSuccess(response.getResult()); + } + + /** + * 根据主键,修改传递字段对应的值 + * + * @param id ES 中的 id + * @param name 姓名 + * @param country 国籍 + * @param age 年龄 + * @param birthday 生日 + * @return UPDATED 代表文档修改成功 + */ + @PutMapping("/person/{id}") + public ApiResponse update(@PathVariable String id, @RequestParam(value = "name", required = false) String name, @RequestParam(value = "country", required = false) String country, @RequestParam(value = "age", required = false) Integer age, @RequestParam(value = "birthday", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birthday) { + UpdateRequest request = new UpdateRequest(INDEX, TYPE, id); + try { + XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); + if (!Strings.isNullOrEmpty(name)) { + builder.field("name", name); + } + if (!Strings.isNullOrEmpty(country)) { + builder.field("country", country); + } + if (age != null && age > 0) { + builder.field("age", age); + } + if (birthday != null) { + builder.field("birthday", birthday.getTime()); + } + builder.endObject(); + request.doc(builder); + } catch (IOException e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + try { + UpdateResponse response = esClient.update(request).get(); + return ApiResponse.ofSuccess(response); + } catch (Exception e) { + e.printStackTrace(); + return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); + } + } + + /** + * 简单查询 根据 id 查 ES 中的文档内容 + * + * @param id ES 中存储的 id + * @return 对应 id 的文档内容 + */ + @GetMapping("/person/{id}") + public ApiResponse get(@PathVariable String id) { + GetResponse response = esClient.prepareGet(INDEX, TYPE, id).get(); + if (!response.isExists() || response.isSourceEmpty()) { + return ApiResponse.ofStatus(Status.NOT_FOUND); + } + return ApiResponse.ofSuccess(response.getSource()); + } + + /** + * 复合查询,根据传进来的条件,查询具体内容 + * + * @param name 根据姓名匹配 + * @param country 根据国籍匹配 + * @param gtAge 大于年龄 + * @param ltAge 小于年龄 + * @return 满足条件的文档内容 + */ + @PostMapping("/person/query") + public ApiResponse query(@RequestParam(value = "name", required = false) String name, + @RequestParam(value = "country", required = false) String country, + @RequestParam(value = "gt_age", defaultValue = "0") int gtAge, + @RequestParam(value = "lt_age", required = false) Integer ltAge) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + + if (!Strings.isNullOrEmpty(name)) { + boolQueryBuilder.must(QueryBuilders.matchQuery("name", name)); + } + + if (!Strings.isNullOrEmpty(country)) { + boolQueryBuilder.must(QueryBuilders.matchQuery("country", country)); + } + + RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").from(gtAge); + + if (ltAge != null && ltAge > 0) { + rangeQueryBuilder.to(ltAge); + } + + boolQueryBuilder.filter(rangeQueryBuilder); + + SearchRequestBuilder searchRequestBuilder = esClient.prepareSearch(INDEX) + .setTypes(TYPE) + .setSearchType(SearchType.DFS_QUERY_THEN_FETCH) + .setQuery(boolQueryBuilder) + .setFrom(0) + .setSize(20); + + log.info("【query】:{}", searchRequestBuilder); + + SearchResponse searchResponse = searchRequestBuilder.get(); + List> result = Lists.newArrayList(); + searchResponse.getHits().forEach(hit -> { + result.add(hit.getSourceAsMap()); + }); + + return ApiResponse.ofSuccess(result); + } + +} diff --git a/spring-boot-demo-elasticsearch/src/main/resources/application.yml b/spring-boot-demo-elasticsearch/src/main/resources/application.yml new file mode 100644 index 0000000..2784476 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/main/resources/application.yml @@ -0,0 +1,8 @@ +server: + port: 8080 + context-path: /demo +elasticsearch: + host: 127.0.0.1 + port: 9300 + cluster: + name: xkcoding diff --git a/spring-boot-demo-elasticsearch/src/test/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplicationTests.java b/spring-boot-demo-elasticsearch/src/test/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplicationTests.java new file mode 100644 index 0000000..7317c62 --- /dev/null +++ b/spring-boot-demo-elasticsearch/src/test/java/com/xkcoding/springbootdemoelasticsearch/SpringBootDemoElasticsearchApplicationTests.java @@ -0,0 +1,16 @@ +package com.xkcoding.springbootdemoelasticsearch; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringBootDemoElasticsearchApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-boot-demo-parent/pom.xml b/spring-boot-demo-parent/pom.xml index 1134d25..987d8c7 100644 --- a/spring-boot-demo-parent/pom.xml +++ b/spring-boot-demo-parent/pom.xml @@ -29,6 +29,7 @@ ../spring-boot-demo-ureport2 ../spring-boot-demo-war ../spring-boot-demo-util + ../spring-boot-demo-elasticsearch @@ -91,7 +92,7 @@ com.google.guava guava - 20.0 + 23.0 org.projectlombok