Skip to content

Commit

Permalink
spring boot 集成 ElasticSearch,采用原生方式集成 ES
Browse files Browse the repository at this point in the history
  • Loading branch information
xkcoding committed Jan 19, 2018
1 parent d70b361 commit d370c79
Show file tree
Hide file tree
Showing 13 changed files with 724 additions and 3 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -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 版本:

Expand Down Expand Up @@ -58,8 +58,11 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu
<module>../spring-boot-demo-orm-mybatis</module>
<module>../spring-boot-demo-cache-redis</module>
<module>../spring-boot-demo-swagger</module>
<module>../spring-boot-demo-rabc-shiro-mybatis</module>
<module>../spring-boot-demo-ureport2</module>
<module>../spring-boot-demo-war</module>
<module>../spring-boot-demo-util</module>
<module>../spring-boot-demo-elasticsearch</module>
</modules>

<parent>
Expand Down Expand Up @@ -122,7 +125,7 @@ spring boot demo 是一个用来学习 spring boot 的项目,已经集成 actu
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
<version>23.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
Expand Down Expand Up @@ -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 介绍

Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 的方式)~~

### 备注

Expand Down
24 changes: 24 additions & 0 deletions spring-boot-demo-elasticsearch/.gitignore
Original file line number Diff line number Diff line change
@@ -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/
280 changes: 280 additions & 0 deletions spring-boot-demo-elasticsearch/README.md
Original file line number Diff line number Diff line change
@@ -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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-boot-demo-elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-elasticsearch</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>com.xkcoding</groupId>
<artifactId>spring-boot-demo-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../spring-boot-demo-parent/pom.xml</relativePath>
</parent>

<properties>
<!--默认 Spring-Boot 依赖的 ES 版本是 2.X 版本,这里采用最新版-->
<elasticsearch.version>6.1.1</elasticsearch.version>
</properties>

<dependencies>
<!-- ES -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-elasticsearch</finalName>
</build>

</project>
```

### application.yml

```yaml
server:
port: 8080
context-path: /demo
elasticsearch:
host: 127.0.0.1
port: 9300
cluster:
name: xkcoding
```
ElasticSearchConfig.java
```java
/**
* <p>
* ES 的配置类
* </p>
*
* @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
/**
* <p>
* Person Controller
* </p>
*
* @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<Map<String, Object>> result = Lists.newArrayList();
searchResponse.getHits().forEach(hit -> {
result.add(hit.getSourceAsMap());
});

return ApiResponse.ofSuccess(result);
}

}
```

44 changes: 44 additions & 0 deletions spring-boot-demo-elasticsearch/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-boot-demo-elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-elasticsearch</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>com.xkcoding</groupId>
<artifactId>spring-boot-demo-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../spring-boot-demo-parent/pom.xml</relativePath>
</parent>

<properties>
<!--默认 Spring-Boot 依赖的 ES 版本是 2.X 版本,这里采用最新版-->
<elasticsearch.version>6.1.1</elasticsearch.version>
</properties>

<dependencies>
<!-- ES -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-elasticsearch</finalName>
</build>

</project>
Loading

0 comments on commit d370c79

Please sign in to comment.