【SpringBoot2.0系列11】SpringBoot之@E

作者: 余空啊 | 来源:发表于2018-09-04 17:30 被阅读15次

【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

最后欢迎大家关注一下我的个人公众号。一起交流一起学习,有问必答。


公众号

相关文章

网友评论

    本文标题:【SpringBoot2.0系列11】SpringBoot之@E

    本文链接:https://www.haomeiwen.com/subject/uragwftx.html