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. 发送请求
相关推荐
IT毕设实战小研4 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
一只爱撸猫的程序猿5 小时前
使用Spring AI配合MCP(Model Context Protocol)构建一个"智能代码审查助手"
spring boot·aigc·ai编程
甄超锋5 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
武昌库里写JAVA8 小时前
JAVA面试汇总(四)JVM(一)
java·vue.js·spring boot·sql·学习
Pitayafruit9 小时前
Spring AI 进阶之路03:集成RAG构建高效知识库
spring boot·后端·llm
zru_96029 小时前
Spring Boot 单元测试:@SpyBean 使用教程
spring boot·单元测试·log4j
甄超锋9 小时前
Java Maven更换国内源
java·开发语言·spring boot·spring·spring cloud·tomcat·maven
还是鼠鼠10 小时前
tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
java·spring boot·后端·spring·maven
舒一笑15 小时前
Started TttttApplication in 0.257 seconds (没有 Web 依赖导致 JVM 正常退出)
jvm·spring boot·后端
javadaydayup16 小时前
Apollo 凭什么能 “干掉” 本地配置?
spring boot·后端·spring