@@ -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 | |||
<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> | |||
@@ -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> | |||
@@ -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 介绍 | |||
@@ -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 的方式)~~ | |||
### 备注 | |||
@@ -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/ |
@@ -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); | |||
} | |||
} | |||
``` | |||
@@ -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> |
@@ -0,0 +1,26 @@ | |||
package com.xkcoding.springbootdemoelasticsearch; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
/** | |||
* <p> | |||
* 应用启动类 | |||
* </p> | |||
* | |||
* @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); | |||
} | |||
} |
@@ -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; | |||
/** | |||
* <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; | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
package com.xkcoding.springbootdemoelasticsearch.web.base; | |||
import lombok.Data; | |||
/** | |||
* <p> | |||
* 统一接口返回类型 | |||
* </p> | |||
* | |||
* @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); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
package com.xkcoding.springbootdemoelasticsearch.web.base; | |||
import lombok.Getter; | |||
/** | |||
* <p> | |||
* 通用状态码 | |||
* </p> | |||
* | |||
* @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; | |||
} | |||
} |
@@ -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; | |||
/** | |||
* <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); | |||
} | |||
} |
@@ -0,0 +1,8 @@ | |||
server: | |||
port: 8080 | |||
context-path: /demo | |||
elasticsearch: | |||
host: 127.0.0.1 | |||
port: 9300 | |||
cluster: | |||
name: xkcoding |
@@ -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() { | |||
} | |||
} |
@@ -29,6 +29,7 @@ | |||
<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> | |||
@@ -91,7 +92,7 @@ | |||
<dependency> | |||
<groupId>com.google.guava</groupId> | |||
<artifactId>guava</artifactId> | |||
<version>20.0</version> | |||
<version>23.0</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.projectlombok</groupId> | |||