专栏首页yukong的小专栏【SpringBoot2.0系列11】SpringBoot之@Elasticsearch完成CURD

【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 条评论
登录 后参与评论

相关文章

  • 【SpringBoot2.0系列12】SpringBoot之JavaMail发送,支持FreeMark模板渲染

    大家都知道邮件协议有两个 smtp:邮件发送协议 pop3:邮件接收协议 我们现在要实现的邮件发送,那么重点就要放在smtp上。 在这里我们借助第三的邮...

    yukong
  • 【SpringSecurity系列01】初识SpringSecurity

    ​ 用自己的话 简单介绍一下,Spring Security基于 Servlet 过滤器链的形式,为我们的web项目提供认证与授权服务。它来自于S...

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

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

    yukong
  • Android项目开发全程(三)-- 项目的前期搭建、网络请求封装是怎样实现的

      在前两篇博文中已经做了铺垫,下面咱们就可以用前面介绍过的内容开始做一个小项目了(项目中会用到Afinal框架,不会用Afinal的童鞋可以先看一下上一篇博文...

    codingblock
  • [设计模式]之十三:抽象工厂模式

    抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。

    wOw
  • 09-TypeScript中的继承

    在后端开发语言中,继承是非常重要的概念,继承可以让子类具有父类的成员和方法,通过实例化子类,就可以访问父类的成员和方法。 在JavaScript中,需要通过原型...

    用户1910585
  • SpringBoot基础篇Bean之条件注入@ConditionalOnProperty

    bean的条件注入,除了前面两篇博文分别介绍的通过@Conditional注解配合Condition接口的基本实现,以及如何使用条件注解@Conditional...

    一灰灰blog
  • 设计模式之状态模式

    Allow an object to alter its behavior when its internal state changes. The objec...

    beginor
  • Spring 注解开发之 @Conditional

    在 SpringBoot 中经常看到该注解及其衍生注解,它的作用是根据条件注入组件。

    wsuo
  • spring之配置单例的集合bean,以供多个bean进行引用

    这种情况下,是在一个bean的里面进行配置的,假设现在我们有另外一个bean,也需要使用List集合里的bean,那么应该怎么做呢?

    绝命生

扫码关注云+社区

领取腾讯云代金券