SpringBoot--中间件技术-3:整合mongodb,整合ElasticSearch,附案例含代码(简单易懂)

SpringBoot整合mongodb

实现步骤:

  1. pom文件导坐标

    xml 复制代码
    <!--mongo-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  2. yaml配置文件配置mongodb:

    yaml 复制代码
    spring:
      data:
        mongodb:
          uri: mongodb://localhost/spring
  3. 随便建一个pojo

    java 复制代码
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Book {
        private int id;
        private String name;
        private String type;
        private String description;
    }
  4. 测试:

    java 复制代码
    @SpringBootTest
    class SpringbootMongodb01ApplicationTests {
    
      @Autowired(required = false)
      private MongoTemplate mongoTemplate;
    
      @Test
      void contextLoads() {
        Book book = new Book();
        book.setId(4);
        book.setName("董健翔");
        book.setType("牛逼");
        book.setDescription("真牛逼");
        mongoTemplate.save(book);
      }
    
      @Test
      void find(){
        List<Book> all = mongoTemplate.findAll(Book.class);
        System.out.println(all);
      }
    }

    装配MongoTemplate模板类,调用方法

整合MongoDB总结:

  1. 导坐标
  2. 写配置文件
  3. 核心类MongoTemplate调用

SpringBoot整合ElasticSearch

前提准备:数据库+ES

数据库建表语句:

sql 复制代码
DROP TABLE IF EXISTS `tb_hotel`;
CREATE TABLE `tb_hotel`  (
  `id` bigint(20) NOT NULL COMMENT '酒店id',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店名称',
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店地址',
  `price` int(10) NOT NULL COMMENT '酒店价格',
  `score` int(2) NOT NULL COMMENT '酒店评分',
  `brand` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店品牌',
  `city` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所在城市',
  `star_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '酒店星级,1星到5星,1钻到5钻',
  `business` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商圈',
  `latitude` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '纬度',
  `longitude` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '经度',
  `pic` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '酒店图片',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

实现步骤:

  1. pom文件到坐标

    xml 复制代码
    <properties>
      <!--锁定jdk版本-->
      <java.version>1.8</java.version>
      <!--锁定es版本-->
      <elasticsearch.version>7.12.0</elasticsearch.version>
    </properties>
    
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
    
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
      </dependency>
    
      <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
      </dependency>
    
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
      </dependency>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
      </dependency>
      <!--FastJson-->
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.71</version>
      </dependency>
    </dependencies>
  2. yaml配置文件

    yaml 复制代码
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/spring?serverTimezone=GMT
        username: root
        password: 123456
    logging:
      level:
        com.dong: debug
    mybatis-plus:
      configuration:
        map-underscore-to-camel-case: true
      type-aliases-package: com.dong.pojo
  3. 创建实体类:

    对应数据库表的实体类

    java 复制代码
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @TableName("tb_hotel")
    public class Hotel {
      @TableId(type = IdType.INPUT)
      private Long id;
      private String name;
      private String address;
      private Integer price;
      private Integer score;
      private String brand;
      private String city;
      private String starName;
      private String business;
      private String longitude;//经度
      private String latitude;//纬度
      private String pic;
    }

    对应ES的实体类

    java 复制代码
    @Data
    @NoArgsConstructor
    public class HotelDoc {
      private Long id;
      private String name;
      private String address;
      private Integer price;
      private Integer score;
      private String brand;
      private String city;
      private String starName;
      private String business;
      private String location;
      private String pic;
    // 构造方法用于类型转换   将数据库中的经、纬度用坐标location代替,所以HotelDoc稍有不同
      public HotelDoc(Hotel hotel){   
        this.id = hotel.getId();
        this.name = hotel.getName();
        this.address = hotel.getAddress();
        this.price = hotel.getPrice();
        this.score = hotel.getScore();
        this.brand = hotel.getBrand();
        this.city = hotel.getCity();
        this.starName = hotel.getStarName();
        this.business = hotel.getBusiness();
        this.location = hotel.getLatitude() + ", "+ hotel.getLongitude();
        this.pic = hotel.getPic();
      }
    }
  4. mapper层:

    java 复制代码
    @Mapper
    public interface HotelMapper extends BaseMapper<Hotel> {
    }
  5. service层:

    接口:

    java 复制代码
    public interface IHotelService extends IService<Hotel> {
    }

    实现类:

    java 复制代码
    @Service
    public class HotelServiceImp extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    }
  6. 演示在juint中进行,演示对索引库和文档的操作

索引库的操作

  • 判断索引库是否存在(其实就是查询)
  • 创建索引库
  • 删除索引库
java 复制代码
@SpringBootTest
class SpringbootEs01ApplicationTests {
	// 操作es的核心对象
  private RestHighLevelClient client;
	// 单元测试之前都执行的,告诉核心对象es的端口号  固定语法
  @BeforeEach
  void setUp(){
    this.client = new RestHighLevelClient(RestClient.builder(
      HttpHost.create("http://localhost:9200")
    ));
  }
	// 单元测试之后都执行的
  @AfterEach
  void tearDown() throws Exception{
    this.client.close();
  }

  // 判断索引库是否存在
  @Test
  void testExistsHotelIndex() throws Exception {
    GetIndexRequest request = new GetIndexRequest("hotels");
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    System.err.println(exists ? "索引库已经存在":"索引库不存在");
  }

  // 创建索引库
  @Test
  void createHotelIndex() throws Exception{
    // 创建Request对象
    CreateIndexRequest request = new CreateIndexRequest("hotels");
    // 准备请求的参数:DSL语句
    request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON);
    // 发送请求
    client.indices().create(request,RequestOptions.DEFAULT);
  }

  // 删除索引库
  @Test
  void delteHotelIndex() throws Exception{
    // 创建Request对象
    DeleteIndexRequest request = new DeleteIndexRequest("hotels");
    // 发送请求
    client.indices().delete(request,RequestOptions.DEFAULT);
  }
}

创建索引库的时候需要映射,映射往往是一个复杂且长的JSON,所以单独写个类,上面创建索引库的映射如下

可以在postman中写好粘贴过来

java 复制代码
public class HotelConstants {
  public static final String MAPPING_TEMPLATE = "{\n" +
    "  \"mappings\": {\n" +
    "    \"properties\": {\n" +
    "      \"id\": {\n" +
    "        \"type\": \"keyword\"\n" +
    "      },\n" +
    "      \"name\":{\n" +
    "        \"type\": \"text\",\n" +
    "        \"analyzer\": \"ik_max_word\",\n" +
    "        \"copy_to\": \"all\"\n" +
    "      },\n" +
    "      \"address\":{\n" +
    "        \"type\": \"keyword\",\n" +
    "        \"index\": false\n" +
    "      },\n" +
    "      \"price\":{\n" +
    "        \"type\": \"integer\"\n" +
    "      },\n" +
    "      \"score\":{\n" +
    "        \"type\": \"integer\"\n" +
    "      },\n" +
    "      \"brand\":{\n" +
    "        \"type\": \"keyword\",\n" +
    "        \"copy_to\": \"all\"\n" +
    "      },\n" +
    "      \"city\":{\n" +
    "        \"type\": \"keyword\",\n" +
    "        \"copy_to\": \"all\"\n" +
    "      },\n" +
    "      \"starName\":{\n" +
    "        \"type\": \"keyword\"\n" +
    "      },\n" +
    "      \"business\":{\n" +
    "        \"type\": \"keyword\"\n" +
    "      },\n" +
    "      \"location\":{\n" +
    "        \"type\": \"geo_point\"\n" +
    "      },\n" +
    "      \"pic\":{\n" +
    "        \"type\": \"keyword\",\n" +
    "        \"index\": false\n" +
    "      },\n" +
    "      \"all\":{\n" +
    "        \"type\": \"text\",\n" +
    "        \"analyzer\": \"ik_max_word\"\n" +
    "      }\n" +
    "    }\n" +
    "  }\n" +
    "}";
}

文档的操作

java 复制代码
@SpringBootTest
public class HotelDocumentTests {
  // 核心对象
  private RestHighLevelClient client;

  // 需要从数据库中查数据存入es,装配业务
  @Autowired(required = false)
  private IHotelService service;

  @BeforeEach
  void setUp(){
    this.client = new RestHighLevelClient(RestClient.builder(
      HttpHost.create("http://localhost:9200")
    ));
  }

  @AfterEach
  void tearDown() throws  Exception{
    this.client.close();
  }

  // 从数据库新增一条数据到es
  @Test
  void addDocument() throws Exception{
    // 从数据库查询一条数据
    Hotel hotel = service.getById(395434);
    System.out.println(hotel);
    // 转换为文档类型
    HotelDoc hotelDoc = new HotelDoc(hotel);
    // 将文档类型转为JSON格式
    String json = JSON.toJSONString(hotelDoc);
    // 准备request请求对象
    IndexRequest request = new IndexRequest("hotels").id(hotelDoc.getId().toString());
    // 准备JSON文档
    request.source(json, XContentType.JSON);
    // 发送请求
    client.index(request, RequestOptions.DEFAULT);
  }

  // 从es中删除一条数据
  @Test
  void deleteDocument() throws Exception{
    // 准备删除请求Request
    DeleteRequest request = new DeleteRequest("hotels", "395434");
    // 发送请求
    client.delete(request,RequestOptions.DEFAULT);
  }

  // 修改es中的数据
  @Test
  void updateDocument() throws  Exception{
    // 准备修改请求UpdateRequest
    UpdateRequest request = new UpdateRequest("hotels", "395434");
    // 准备请求参数(要修改的数据内容)
    request.doc(
      "name","W酒店",
      "city","西安",
      "price","2000",
      "starName","五星级"
    );
    // 发送请求
    client.update(request, RequestOptions.DEFAULT);
  }

  // 从es中查询一条数据
  @Test
  void getDocumentById() throws  Exception{
    // 准备查询请求GetRequest
    GetRequest getRequest = new GetRequest("hotels", "395434");
    // 发送请求,得到响应
    GetResponse response = client.get(getRequest, RequestOptions.DEFAULT);
    // 解析响应结果
    String json = response.getSourceAsString();
    HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
    System.out.println(hotelDoc);
  }

  // 批量新增数据到es
  @Test
  void addAllDocument() throws  Exception{
    // 数据库全查
    List<Hotel> hotels = service.list();
    // 准备请求
    BulkRequest bulkRequest = new BulkRequest();
    // 准备参数
    for(Hotel hotel : hotels){
      // 类型转化
      HotelDoc hotelDoc = new HotelDoc(hotel);
      // 请求添加数据
      bulkRequest.add(new IndexRequest("hotels").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc),XContentType.JSON));
    }
    // 发送请求
    client.bulk(bulkRequest,RequestOptions.DEFAULT);
  }

  // 解析对象方法
  public void show(SearchResponse response){
    // 解析响应
    SearchHits searchHits = response.getHits();
    long total = searchHits.getTotalHits().value;
    System.out.println("总计查询数据:"+total+"条");
    SearchHit[] hits = searchHits.getHits();
    for(SearchHit hit :hits){
      /// 获取文档source
      String json = hit.getSourceAsString();
      // 反序列化
      HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
      System.out.println("hotelDoc="+hotelDoc);
    }
  }
  /*---------- 全查 ------------*/
  // 全查
  @Test
  void findAllDocument() throws IOException{
    // 准备request
    SearchRequest request = new SearchRequest("hotels");

    // 2.准备DSL,QueryBuilders构造查询条件
    request.source().query(QueryBuilders.matchAllQuery());

    // 3.发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  /*-------------- 全文检索 ---------------*/
  // 查询all字段内容中含有如家的
  @Test
  void testMacth() throws IOException{
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备DSL
    request.source().
      query(QueryBuilders.matchQuery("all","如家"));

    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  // 查询字段name、city中有上海的
  @Test
  void testMultiMatchQuery()throws IOException {
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备DSL
    request.source()
      .query(QueryBuilders.multiMatchQuery("上海","name","city"));
    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  /*------------ 精确查询 ------------------*/

  // term:根据词条精准查询(字段等值查询)
  @Test
  void testTerm() throws  IOException{
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备DSL
    request.source()
      .query(QueryBuilders.termQuery("brand","希尔顿"));

    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  // range范围查询
  @Test
  void  testRange() throws IOException {
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备DSL
    request.source()
      .query(QueryBuilders.rangeQuery("price").gte(200).lte(300));
    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  // ids查询
  @Test
  void testIds() throws IOException  {
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备DSL
    request.source()
      .query(QueryBuilders.idsQuery().addIds("395434","3532"));
    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  /*------------- 复合查询 --------------------*/
  // bool复合查询
  @Test
  void testBool() throws IOException{
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    // 准备条件
    /*-- 方式1  ----*/
    //        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    //        boolQueryBuilder.must(QueryBuilders.termQuery("city","北京"));
    //        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(500));
    //        // 准备DSL
    //        request.source().query(boolQueryBuilder);

    /*---- 方式2 ----*/
    request.source()
      .query(QueryBuilders.boolQuery()
             .must(QueryBuilders.termQuery("city","北京"))
             .filter(QueryBuilders.rangeQuery("price").lte(500)));
    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    show(response);
  }

  // 自定义分页方式
  @Test
  void testPageAndSort() throws IOException{
    int page = 1;   //页码
    int size = 5;   //步长
    String searchName="希尔顿"; // 查询条件
    // 准备请求
    SearchRequest request = new SearchRequest("hotels");
    if (searchName == null){
      request.source().query(QueryBuilders.matchAllQuery());
    }else {
      request.source().query(QueryBuilders.matchQuery("brand",searchName));
    }
    // 自定义分页
    request.source().from((page-1)*size).size(size);
    // 自定义排序
    request.source().sort("price", SortOrder.DESC);
    // 发送请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 解析结果
    show(response);
  }
}

小结:

文档的查询操作实现步骤大致都相同:

  1. 准备请求
  2. 准备DSL
  3. 发送请求
相关推荐
JH30738 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
qq_124987075311 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_11 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_8187320611 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu15 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶15 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip16 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide16 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf17 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva17 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端