前面了解了使用 HTTP 请求操作 ES,但是实际项目中操作,我们主要还是使用Java代码操作,所以尝试一下Java客户端连接ES

基础

  1. 已安装ES,且自己能够正常操作API,了解ES基本语法
  2. 本地已安装IDE

新建springboot工程

  1. pom.xml,主要是加入ES的依赖就好,版本号与ES服务器版本号一致,我的都是6.5.1
    <?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>
    
        <groupId>com.elastic</groupId>
        <artifactId>es-1</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>es-1</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/transport -->
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>transport</artifactId>
                <version>6.5.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

     

  2. 客户端连接服务器,通过TransportClient,这里直接获取连接然后注入容器
    package com.elastic.es1;
    
    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.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    @Configuration
    @SpringBootApplication
    @ComponentScan("com.elastic.es1")
    public class Es1Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Es1Application.class, args);
        }
    
        @Bean
        public TransportClient client() throws UnknownHostException {
    
            String hostName = "47.105.159.23";
            TransportAddress transportAddress = new TransportAddress(InetAddress.getByName(hostName), 9300);
    
            String clusterName = "cluster.name";
            String nodeName = "gaojie";
            Settings settings = Settings.builder().put(clusterName, nodeName).build();
            TransportClient client = new PreBuiltTransportClient(settings);
            client.addTransportAddress(transportAddress);
            return client;
        }
    
    }
    

     

  3. 编写实体类,此处操作的是一个 employee 对象
    public class EmployeeVo {
    
        private String id;      // ID
        private String name;    // 姓名
        private String phone;   // 电话
        private Integer sex;    // 性别
        private Integer salary;  // 工资
        private String post;    // 岗位
        private String desc;    // 描述
        private Date joinTime;  // 入职时间
    
        private String keyword;     // 关键字
        private Integer minSalary;  // 最小工资
        private Integer maxSalary;  // 最大工资
        private Date startTime;     // 开始时间
        private Date endTime;       // 结束时间
        private Set<String> ids;    // ID集合
    
        private Object data;        // 查询结果
        private Long total;      // 查询记录总数
        private Integer from;       // 起始位置
        private Integer size;       // 查询条数
    
        public EmployeeVo(Object data, Long total) {
            this.data = data;
            this.total = total;
        }
    }

     

  4. 编写接口类,定义方法以及常量,避免便于维护和可读
    package com.elastic.es1.service.interfaces;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    
    import java.io.IOException;
    
    public interface EmployeeService {
    
        void save(EmployeeVo vo) throws IOException;
    
        void delete(EmployeeVo vo);
    
        EmployeeVo search(EmployeeVo vo);
    
        String INDEX = "manage";
        String TYPE = "employee";
    
        String NAME = "name";
        String PHONE = "phone";
        String SEX = "sex";
        String SALARY = "salary";
        String POST = "post";
        String DESC = "desc";
        String JOIN_TIME = "joinTime";
    
    }
    

     

  5. 方法实现(save方法,当传入ID时为修改,不传ID时为新增)
    package com.elastic.es1.service.impl;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    import com.elastic.es1.service.interfaces.EmployeeService;
    import org.elasticsearch.action.search.SearchRequestBuilder;
    import org.elasticsearch.action.search.SearchType;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.xcontent.XContentBuilder;
    import org.elasticsearch.index.query.BoolQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.index.query.RangeQueryBuilder;
    import org.elasticsearch.search.SearchHits;
    import org.elasticsearch.search.sort.SortBuilders;
    import org.elasticsearch.search.sort.SortOrder;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
    
    @Service
    public class EmployeeServiceImpl implements EmployeeService {
    
        @Resource
        private TransportClient client;
    
        @Override
        public void save(EmployeeVo vo) throws IOException {
            XContentBuilder builder = this.getBuilder(vo);
            if (vo.getId() == null) {
                // 若不传入 ID 则表示新增
                client.prepareIndex(INDEX, TYPE).setSource(builder).get();
            } else {
                // 若传入 ID 则表示修改
                client.prepareUpdate(INDEX, TYPE, vo.getId()).setDoc(builder).get();
            }
        }
    
        /**
         * 将请求对象 EmployeeVo 转换成 builder 对象
         */
        private XContentBuilder getBuilder(EmployeeVo vo) throws IOException {
            XContentBuilder builder = jsonBuilder().startObject();
            if (vo.getName() != null) {
                builder.field(NAME, vo.getName());
            }
            if (vo.getPhone() != null) {
                builder.field(PHONE, vo.getPhone());
            }
            if (vo.getPost() != null) {
                builder.field(POST, vo.getPost());
            }
            if (vo.getDesc() != null) {
                builder.field(DESC, vo.getDesc());
            }
            if (vo.getSex() != null) {
                builder.field(SEX, vo.getSex());
            }
            if (vo.getSalary() != null) {
                builder.field(SALARY, vo.getSalary());
            }
            return builder.endObject();
        }
    
        @Override
        public void delete(EmployeeVo vo) {
            if (vo.getIds() != null) {
                vo.getIds().forEach(id -> client.prepareDelete(INDEX, TYPE, id).get());
            }
        }
    
        @Override
        public EmployeeVo search(EmployeeVo vo) {
    
            // boolQuery :可以叠加多个查询条件,相当于SQL的 AND
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // multiMatchQuery :多字段搜索,输入关键字,可以从多个字段匹配
            if (vo.getKeyword() != null) {
                boolQueryBuilder.must(QueryBuilders.multiMatchQuery(vo.getKeyword(), NAME, PHONE, POST, DESC));
            }
            // matchQuery :单字段搜索
            if (vo.getName() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(NAME, vo.getName()));
            }
            // wildcardQuery :通配符匹配:类似于SQL里面的 LIKE
            if (vo.getPhone() != null) {
                boolQueryBuilder.must(QueryBuilders.wildcardQuery(PHONE, "*" + vo.getPhone() + "*"));
            }
            if (vo.getPost() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(POST, vo.getPost()));
            }
            if (vo.getDesc() != null) {
                boolQueryBuilder.must(QueryBuilders.matchQuery(DESC, vo.getDesc()));
            }
            // termQuery : 通常用于非字符串类型的比较,比如性别为男的或者女的,状态为1或者2什么的。。总之比较固定值
            if (vo.getSex() != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery(SEX, vo.getSex()));
            }
            if (vo.getSalary() != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery(SALARY, vo.getSalary()));
            }
            // rangeQuery :范围查询,判断一个值是否在范围内,比如工资大于多少,年龄多少之间,是否在有效期内。。。
            if (vo.getMinSalary() != null || vo.getMaxSalary() != null) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(SALARY);
                if (vo.getMinSalary() != null) {
                    // from :范围查询里面的下限值,包含该值
                    rangeQueryBuilder.from(vo.getMinSalary());
                }
                if (vo.getMaxSalary() != null) {
                    // to :范围查询里面的上限值,包含该值
                    rangeQueryBuilder.to(vo.getMaxSalary());
                }
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if (vo.getStartTime() != null || vo.getEndTime() != null) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(JOIN_TIME);
                if (vo.getStartTime() != null) {
                    rangeQueryBuilder.from(vo.getStartTime());
                }
                if (vo.getEndTime() != null) {
                    rangeQueryBuilder.to(vo.getEndTime());
                }
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            SearchRequestBuilder searchRequestBuilder = client.prepareSearch(INDEX).setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setQuery(boolQueryBuilder);
            // from :翻页参数,从第几条记录开始
            if (vo.getFrom() != null) {
                searchRequestBuilder.setFrom(vo.getFrom());
            }
            // size :翻页参数,查询的记录数
            if (vo.getSize() != null) {
                searchRequestBuilder.setSize(vo.getSize());
            }
    
            // sort : 排序规则,默认规则为ASC升序,可以修改排序规则也可以用多个字段
            searchRequestBuilder.addSort(SortBuilders.fieldSort(SEX))
                    .addSort(SortBuilders.fieldSort(SALARY).order(SortOrder.DESC));
    
            System.out.println("查询条件为|" + searchRequestBuilder);
    
            // 查询结果,由于数据都在 sourceAsMap 参数下,所以下面会再获取 sourceAsMap 的值
            SearchHits hits = searchRequestBuilder.get().getHits();
    
            List<Map<String, Object>> data = new ArrayList<>();
            hits.forEach(hit -> {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                sourceAsMap.put("_id", hit.getId());
                data.add(sourceAsMap);
            });
    
            return new EmployeeVo(data, hits.totalHits);
        }
    }
    

     

  6. 编写 Controller
    package com.elastic.es1.controller;
    
    import com.elastic.es1.entity.vo.EmployeeVo;
    import com.elastic.es1.service.interfaces.EmployeeService;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.io.IOException;
    
    @RestController
    @RequestMapping("employee")
    public class EmployeeController {
    
        @Resource
        private EmployeeService employeeService;
    
        @PostMapping("save")
        public Object save(@RequestBody EmployeeVo vo) throws IOException {
            employeeService.save(vo);
            return "保存成功";
        }
    
        @DeleteMapping("delete")
        public Object delete(@RequestBody EmployeeVo vo) {
            employeeService.delete(vo);
            return  "删除成功";
        }
    
        @GetMapping("search")
        public Object search(EmployeeVo vo) {
            return employeeService.search(vo);
        }
    
    }
    

     

  7.  修改 application.properties 端口号,因为默认端口为8080,防止冲突
    server.port=9090

     

项目启动成功后,去Postman测试,都能够正常使用,这里只记录一个 search 请求

GET   http://localhost:9090/employee/search?from=0&size=10
================================================
{
    "id": null,
    "name": null,
    "phone": null,
    "sex": null,
    "salary": null,
    "post": null,
    "desc": null,
    "joinTime": null,
    "keyword": null,
    "minSalary": null,
    "maxSalary": null,
    "startTime": null,
    "endTime": null,
    "ids": null,
    "data": [
        {
            "post": "设计前端",
            "phone": "18874797777",
            "sex": 1,
            "name": "桂禄",
            "dept": {
                "name": "设计中心",
                "id": "1003"
            },
            "_id": "o1ZWmGcBof4Qu3GrG81P",
            "salary": 50000,
            "join_time": "2018-05-03",
            "desc": "a front boy"
        },
        {
            "post": "架构师",
            "phone": "18874792222",
            "sex": 1,
            "name": "春哥",
            "dept": {
                "name": "技术中心",
                "id": "1001"
            },
            "_id": "nlb-l2cBof4Qu3Gr8M1Y",
            "salary": 35000,
            "join_time": "2018-03-03",
            "desc": "a framework boy"
        },
        {
            "post": "设计UI",
            "phone": "18874796666",
            "sex": 1,
            "name": "铜川",
            "dept": {
                "name": "设计中心",
                "id": "1003"
            },
            "_id": "olYDmGcBof4Qu3Grw837",
            "salary": 16000,
            "join_time": "2018-04-03",
            "desc": "a sunny boy"
        },
        {
            "post": "Java工程师",
            "phone": "18874796310",
            "sex": 1,
            "name": "高节",
            "dept": {
                "name": "技术中心",
                "id": "1001"
            },
            "_id": "nFZul2cBof4Qu3GrDc0v",
            "salary": 10000,
            "join_time": "2018-12-03",
            "desc": "a love of work boy"
        },
        {
            "post": "IOS工程师",
            "phone": "18874791111",
            "sex": 2,
            "name": "周益",
            "dept": {
                "name": "技术中心",
                "id": "1001"
            },
            "_id": "nVZ-l2cBof4Qu3GrFc1L",
            "salary": 15000,
            "join_time": "2018-10-03",
            "desc": "a IOS boy"
        },
        {
            "post": "测试工程师",
            "phone": "18874793333",
            "sex": 2,
            "name": "丽燕",
            "dept": {
                "name": "技术中心",
                "id": "1001"
            },
            "_id": "n1YAmGcBof4Qu3GrB83o",
            "salary": 12000,
            "join_time": "2018-05-03",
            "desc": "a beautiful girl"
        },
        {
            "post": "Android工程师",
            "phone": "18874794444",
            "sex": 2,
            "name": "李岳",
            "dept": {
                "name": "技术中心",
                "id": "1001"
            },
            "_id": "oFYAmGcBof4Qu3Gr880L",
            "salary": 12000,
            "join_time": "2018-04-03",
            "desc": "a rude man"
        },
        {
            "post": "会计",
            "phone": "18874795555",
            "sex": 2,
            "name": "青萍",
            "dept": {
                "name": "财务部门",
                "id": "1002"
            },
            "_id": "oVYCmGcBof4Qu3Gr8c33",
            "salary": 6000,
            "join_time": "2018-08-03",
            "desc": "a sunny girl"
        }
    ],
    "total": 8,
    "from": null,
    "size": null
}

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐