【SpringBoot2.0系列11】SpringBoot之@Elasticsearch完成CURD

【SpringBoot系列01】初识SpringBoot

【SpringBoot系列02】SpringBoot之使用Thymeleaf视图模板

【SpringBoot系列03】SpringBoot之使用freemark视图模板

【SpringBoot系列04】SpringBoot之使用JPA完成简单的rest api

【SpringBoot系列05】SpringBoot之整合Mybatis

【SpringBoot2.0系列06】SpringBoot之多数据源动态切换数据源

【SpringBoot2.0系列07】SpringBoot之redis使用(Lettuce版本)

【SpringBoot2.0系列08】SpringBoot之redis数据缓存管理

【SpringBoot2.0系列09】SpringBoot之rabbitmq使用

【SpringBoot2.0系列10】SpringBoot之@Scheduled任务调度

【SpringBoot2.0系列11】SpringBoot之@Elasticsearch完成CURD

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。 如果在springboot使用Easticsearch呢。在这里我们使用spring-boot-starter-data-elasticsearch。 它提供一系列简单的api给我们使用,让我们有种操作关系数据库的感觉。 好了话不多说,先说一下环境。

  • spring boot2.x
  • jdk8
  • elasticsearch5.x(6.x也可以)

依赖

引入依赖

  <dependencies>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
        <!-- elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

在这里我们分别引入elasticsearch跟lombok的依赖,关于lombok的介绍大家可以看看这篇文章 讲的很详细。我这简单的介绍一下在项目中使用Lombok可以减少很多重复代码的书写。比如说getter/setter/toString等方法的编写。

配置es地址

在下文中我将用es代替elasticsearch。我们打开application.yml文件 配置如下

  spring:
  data:
    elasticsearch:
      # 集群的名字
      cluster-name: wali
      # 节点的ip与端口 注意端口是9300不是9200
      cluster-nodes: 127.0.0.1:9300

构建文档对象

假设这是一个商品索引goods,他有一个类型是电脑computer。 分别有四个字段

  • id 唯一标识
  • name 商品名称
  • number 商品数量
  • desc 商品具体描述 我们根据上面的描述,编写出对应的实体类
@Data
@ToString
@Accessors(chain = true)
@Document(indexName = "goods", type = "computer")
public class Good {

    /**
     * 主键,注意这个搜索是id类型是string,与我们常用的不同
     * Id注解加上后,在Elasticsearch里相应于该列就是主键了,在查询时就可以直接用主键查询
     */
    @Id
    private String id;

    private String name;

    private String desc;

    private Integer number;

}

其中@Data @ToString @Accessors(chain = true) 是属于lombok注解。

  • @Data 会自动上传get/set方法
  • @ToString 会生成tostring方法
  • @Accessors(chain = true) 会让我们set方法可以链式调用 @Document注解

@Document注解里面的几个属性,类比mysql的话是这样: indexName –> 索引库的名称,建议以项目的名称命名,就相当于数据库DB type –> 类型,建议以实体的名称命名Table ,就相当于数据库中的表table Document –> row 就相当于某一个具体对象

jpa构建文档库

接着,我们可以通过jpa构建文档库,来操作我们的goods对应的文档。 因为我们引入的是spring data的elasticsearch所以它遵循spring data的接口,也就是说操作elasticSearch与操作spring data jpa的方法是完全一样的,我们只将文档库继承ElasticsearchRepository即可。

public interface GoodRepository extends ElasticsearchRepository<Good, String> {

   /**
     * 根据商品名称查询 分页
     * @param name
     * @param pageable
     * @return
     */
    Page<Good> findByName(String name, Pageable pageable);

}

然后创建对应的测试类。前面说过快捷键ctrl+shift+t 并且编写测试方法,我们分别需要测试添加 删除 修改 查询 分页查询方法。

@Component
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class GoodRepositoryTest extends Chapter10ApplicationTests {

    @Autowired
    private GoodRepository goodRepository;
    
    @Test
    public void save(){}

    @Test
    public void update(){}

    @Test
    public void select(){}

    @Test
    public void delete(){}

    @Test
    public void findByName() {
       
    }
}

上面代码我们是通过基础主测试类然后使用@Component注解就可以,这样就不需要每个测试都要@SpringTest注解与@RunWith注解了 另外@FixMethodOrder(MethodSorters.NAME_ASCENDING)这个注解是表示按照方法名的顺序来排序,不然它不会按照我们方法书写的顺序执行,那么就有可能导致,还没save就select,这样就会失败了。 接下来继续编写方法体。goodRepository跟我们直接data-jparespository用法基本一致。都有继承save,delete,find方法的。

@Test
    public void save(){
        Good good = new Good();
        good.setId("100")
                .setName("联想e541")
                .setDesc("联想e系列")
                .setNumber(10);
        Good result = goodRepository.save(good);
        Assert.assertNotNull(result);
    }

    @Test
    public void select(){
        // 需要注意find方法返回的死Optional对象 需要调用get方法返回具体的实体类对象
        Good result = goodRepository.findById("100").get();
        Assert.assertNotNull(result);

    }

    @Test
    public void update(){
        Good result = goodRepository.findById("100").get();
        result.setNumber(300);
        // 更新也是调用save方法
        Good good = goodRepository.save(result);
        Assert.assertNotNull(good);

    }



    @Test
    public void delete(){
        goodRepository.deleteById("100");
    }

我们首先测试增删改查方法。并且通过Assert断言来判断。

image.png

测试通过, 接下来我测试一下分页查询方法,首页我们看一下es中、goods索引computer类别下有哪些文档。

curl -XGET  'http://127.0.0.1:9200/goods/computer/_search?pretty'

结果如下

{
  "took" : 21,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "goods",
        "_type" : "computer",
        "_id" : "_search",
        "_score" : 1.0,
        "_source" : {
          "id" : "_search",
          "name" : "macbook",
          "number" : 20,
          "desc" : "macbook air"
        }
      },
      {
        "_index" : "goods",
        "_type" : "computer",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "id" : "2",
          "name" : "think pad",
          "number" : 20,
          "desc" : "联想旗下thinkpad系列"
        }
      },
      {
        "_index" : "goods",
        "_type" : "computer",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : "1",
          "name" : "macbook",
          "number" : 20,
          "desc" : "macbook pro"
        }
      }
    ]
  }
}

我看到在computer类别中存有三条文档,name分别是 macbook think pad macbook,所以我们查询一下name=macbook的文档,pageSize=1,pageNum=1.

@Test
    public void findByName() {
        String name = "macbook";
        Pageable pageable = new PageRequest(1,1);
        Page<Good> goods = goodRepository.findByName(name, pageable);
        System.out.println(goods.getContent());
        Assert.assertEquals(1, goods.getSize());

    }

我们查询name为macbook的数据,并且限制每页一条,所以我们查询的结果总数应该是一条。结果如下。

在这节,我们了解了springboot与es的curd操作,都是比较简单的,那么下节我们会详细了解springboot对es如何进行复杂查询,与聚合查询。 最后本节的配套代码地址为https://github.com/YuKongEr/SpringBoot-Study/tree/master/chapter10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员的SOD蜜

使用Ring Buffer构建高性能的文件写入程序

最近常收到SOD框架的朋友报告的SOD的SQL日志功能报错:文件句柄丢失。经过分析得知,这些朋友使用SOD框架开发了访问量比较大的系统,由于忘记关闭SQL日志功...

4386
来自专栏Spring相关

第7章—SpringMVC高级技术—处理multipart形式的数据

MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 Mul...

3122
来自专栏GreenLeaves

C# 文件操作系列一

在.Net环境中,所有关于文件操作的类都在System.IO命名空间下,注:在修改文件时,安全性显得格外重要,但是本随笔不过多讲述安全性,这里假设我们有足够的权...

2355
来自专栏玄魂工作室

如何将HTML字符转换为DOM节点并动态添加到文档中

将字符串动态转换为DOM节点,在开发中经常遇到,尤其在模板引擎中更是不可或缺的技术。 字符串转换为DOM节点本身并不难,本篇文章主要涉及两个主题:<br />

1602
来自专栏移动开发之家

Flutter完整开发实战详解(一、Dart语言和Flutter基础)

 在如今的 Fultter 大潮下,本系列是让你看完会安心的文章。本系列将完整讲述:如何快速从0开发一个完整的 Flutter APP,配套高完成度 Flut...

1K2
来自专栏思考的代码世界

Python网络数据采集之HTML解析|第01天

1594
来自专栏Flutter&Dart

Flutter之MaterialApp使用详解

1.2K3
来自专栏Android知识点总结

Android基于TCP的五子棋双人对战实现

1762
来自专栏一个会写诗的程序员的博客

BootstrapTable (前后端分页,表格 ajax 返回数据回调处理) 配置参数全说明

3.8K4
来自专栏冰霜之地

关于IB_DESIGNABLE / IBInspectable的那些需要注意的事

IB_DESIGNABLE / IBInspectable 这两个关键字是在WWDC 2014年"What's New in Interface Builder...

1473

扫码关注云+社区

领取腾讯云代金券