微服务框架 SpringCloud微服务架构 25 黑马旅游案例 25.3 我附近的酒店

news2024/12/26 0:15:11

微服务框架

【SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】

SpringCloud微服务架构

文章目录

      • 微服务框架
      • SpringCloud微服务架构
      • 25 黑马旅游案例
        • 25.3 我附近的酒店
          • 25.3.1 直接开干

25 黑马旅游案例

25.3 我附近的酒店

25.3.1 直接开干

案例:案例3:我附近的酒店

前端页面点击定位后,会将你所在的位置发送到后台:

在这里插入图片描述

在这里插入图片描述

像下面这样

在这里插入图片描述

在这里插入图片描述

这里要浏览器获取定位权限,谷歌和Edge 的定位引擎可能会导致无法定位,比如谷歌用的谷歌地图,咱们国内想“直接”使用谷歌地图…还是算了,建议直接开火狐

我们要根据这个坐标,将酒店结果按照到这个点的距离升序排序。

实现思路如下:

  • 修改RequestParams参数,接收location字段
  • 修改search方法业务逻辑,如果location有值,添加根据geo_distance排序的功能

【距离排序】

距离排序与普通字段排序有所差异,API如下:

在这里插入图片描述

OK,

先改下请求参数实体类

package cn.itcast.hotel.pojo;

import lombok.Data;

/**
 * ClassName: RequestParams
 * date: 2022/11/2 11:03
 *
 * @author DingJiaxiong
 */

@Data
public class RequestParams {

    private String key;
    private Integer page;
    private Integer size;
    private String sortBy;

    private String city;
    private String brand;
    private String starName;
    private Integer minPrice;
    private Integer maxPrice;
    
    private String location;

}

直接修改业务代码

package cn.itcast.hotel.service.impl;

import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PBEParameterSpec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageResult search(RequestParams params) {

        try {
            //1. 准备Request
            SearchRequest request = new SearchRequest("hotel");
            //2. 准备DSL
            //2.1 关键字搜索query

            buildBasicQuery(params, request);

            //2.2 分页
            Integer page = params.getPage();
            Integer size = params.getSize();
            request.source().from((page - 1) * size).size(size);

            //2.3 排序
            String location = params.getLocation();
            if (location != null && !location.equals("")) {
                request.source().sort(SortBuilders
                        .geoDistanceSort("location", new GeoPoint(location))
                        .order(SortOrder.ASC)
                        .unit(DistanceUnit.KILOMETERS)
                );
            }

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

            //4. 解析响应
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void buildBasicQuery(RequestParams params, SearchRequest request) {
        //构建BooleanQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //关键字搜索
        String key = params.getKey();
        //健壮判断
        if (key == null || "".equals(key)) {
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        }
        //条件过滤
        //【城市】
        if (params.getCity() != null && !params.getCity().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }

        //【品牌】
        if (params.getBrand() != null && !params.getBrand().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }

        //【星级】
        if (params.getStarName() != null && !params.getStarName().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }

        //【价格】
        if (params.getMinPrice() != null && params.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders
                    .rangeQuery("price")
                    .gte(params.getMinPrice())
                    .lte(params.getMaxPrice()));
        }

        request.source().query(boolQuery);
    }

    private PageResult handleResponse(SearchResponse response) {
        //4. 解析响应
        SearchHits searchHits = response.getHits();
        //4.1 获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");

        //4.2 文档数组
        SearchHit[] hits = searchHits.getHits();

        //4.3 遍历
        List<HotelDoc> hotels = new ArrayList<>();

        for (SearchHit hit : hits) {
            //获取文档source
            String json = hit.getSourceAsString();
            //反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            hotels.add(hotelDoc);
        }

        //4.4 封装返回
        return new PageResult(total, hotels);
    }
}

先直接重启试试

在这里插入图片描述

啊这,我在兰州、为什么要找深圳的酒店…【继续往下做了】

记下我当前位置的经纬度,35.940046, 104.157428

在kibana 测试一下

# 找到35.940046, 104.157428 周围的酒店,距离升序排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 35.940046,
          "lon": 104.157428
        },
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

直接运行

在这里插入图片描述

行的,最近的距离我1118km,【应该是直线距离】

在这里插入图片描述

按照距离排序后,还需要显示具体的距离值:

先给实体类来个新的属性【距离】

在这里插入图片描述

package cn.itcast.hotel.service.impl;

import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PBEParameterSpec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageResult search(RequestParams params) {

        try {
            //1. 准备Request
            SearchRequest request = new SearchRequest("hotel");
            //2. 准备DSL
            //2.1 关键字搜索query

            buildBasicQuery(params, request);

            //2.2 分页
            Integer page = params.getPage();
            Integer size = params.getSize();
            request.source().from((page - 1) * size).size(size);

            //2.3 排序
            String location = params.getLocation();
            if (location != null && location.equals("")) {
                request.source().sort(SortBuilders
                        .geoDistanceSort("location", new GeoPoint(location))
                        .order(SortOrder.ASC)
                        .unit(DistanceUnit.KILOMETERS)
                );
            }

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

            //4. 解析响应
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void buildBasicQuery(RequestParams params, SearchRequest request) {
        //构建BooleanQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //关键字搜索
        String key = params.getKey();
        //健壮判断
        if (key == null || "".equals(key)) {
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        }
        //条件过滤
        //【城市】
        if (params.getCity() != null && !params.getCity().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }

        //【品牌】
        if (params.getBrand() != null && !params.getBrand().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }

        //【星级】
        if (params.getStarName() != null && !params.getStarName().equals("")) {
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }

        //【价格】
        if (params.getMinPrice() != null && params.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders
                    .rangeQuery("price")
                    .gte(params.getMinPrice())
                    .lte(params.getMaxPrice()));
        }

        request.source().query(boolQuery);
    }

    private PageResult handleResponse(SearchResponse response) {
        //4. 解析响应
        SearchHits searchHits = response.getHits();
        //4.1 获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");

        //4.2 文档数组
        SearchHit[] hits = searchHits.getHits();

        //4.3 遍历
        List<HotelDoc> hotels = new ArrayList<>();

        for (SearchHit hit : hits) {
            //获取文档source
            String json = hit.getSourceAsString();
            //反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);

            //获取排序值
            Object[] sortValues = hit.getSortValues();
            if (sortValues.length > 0){
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }

            hotels.add(hotelDoc);
        }

        //4.4 封装返回
        return new PageResult(total, hotels);
    }
}

直接重启服务

在这里插入图片描述

在这里插入图片描述

厉害厉害

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/71699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成大题分析(四)

假设计算机 M 的主存地址为 24 位,按字节编址,采用分页存储管理方式,虚拟地址为 30 位,页大小为 4KB,TLB 采用 2 路组相联方式 和LRU 替换策略,一共8组。请回答一下问题。 (1) 虚拟地址中有哪几位表示虚页号? 哪几位表示内存地址? (2)己知访问 TLB 时虚页号高位部分用作 TLB…

留学Assignment写作语法错误怎么改正?

如何避免Assignment写作中的一些语法错误&#xff0c;在留学生提交论文要求进行润色修改时&#xff0c;经常会碰到一些语法上的错误&#xff0c;这都是英语水平的问题&#xff0c;同时也与自身的习惯相关&#xff0c;下面小编说一下Assignment写作的语法错误的几种情况&#xf…

浙江省AAA级“守合同重信用”公示企业

浙江省“守合同重信用”企业公示&#xff0c;是市场监管部门依企业自愿申请&#xff0c;对符合公示条件企业前两个年度内的合同履约信息向社会公示的行政指导行为。 浙江省“守合同重信用”企业公示实行逐级推荐、分级公示、动态管理制度。企业住所地县级市场监管局受理企业公示…

你还在使用swagger?试试这个吧

文章目录easyyapi插件使用1. 安装插件2. 配置插件3. 编写javadoc4. 上传接口javadoc5. 登录YApi,查看项目接口easyyapi插件使用 1. 安装插件 打开idea的Settings–>Plugins,查找easyyapi插件安装。 2. 配置插件 安装成功后&#xff0c;再次打开Settings–>OtherSett…

公司小程序小程序毕业设计,企业小程序系统设计与实现,微信小程序毕业设计论文怎么写毕设源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序公司企业站系统&#xff0c;前台用户使用小程序&#xff0c;后台管理使用基PHP开发&#xff0c;存储使用Mysql数据库&#xff1b;通过后台添加公司信息、资讯、产品等&#xff0c;用户通过小程…

vue+element+electron仿微信实现

一.仿得太像了有木有~ 1.登录窗口 2.主窗口 二.构思&#xff0c;以微信设计布局构思 以微信布局构思&#xff0c;参考element提供的组件&#xff1b;element提供的tabs标签页刚好能实现切换效果&#xff0c;element tabs 标签页&#xff1b;element tabs标签页虽然能达到切换…

如果把网络原理倒过来看,从无到有,一切如此清晰

从物理层到数据链路层 也从上篇我们创造一个计算机网络&#xff0c;你会去怎么设计&#xff1f;&#xff0c;追溯到计算机网络互联的本质就是通信问题&#xff0c;所以从物理层解决使用何种信号来传输比特的问题。 再从物理设备中的集线器&#xff0c;聊到二层的交换机&#…

零基础CSS入门教程(9)——背景颜色和背景图片

本章目录1.任务目标2.背景颜色3.背景图片4.小结1.任务目标 我们前几小节学习了如何设置字体格式&#xff0c;我们这一小节学习一下如何设置背景颜色和图片 2.背景颜色 我们可以通过background-color给标签设置背景颜色&#xff0c;例如&#xff1a; <!DOCTYPE html> …

【世界杯限定】致敬梅西,用Python刻画足球场上的战神

最近卡塔尔世界杯正在火热的进行着&#xff0c;相信球迷们一定不会错过每一场精彩的比赛吧&#xff0c;在看球的同时&#xff0c;小伙伴们不要忘记自己的学习与工作哦&#xff0c;本人纯属路人&#xff0c;虽然不是很懂球&#xff0c;但是很喜欢梅西&#xff0c;所以我开始关注…

云边协同下的统一应用管理: 基于 OpenYurt 和 KubeVela 的解决方案

作者&#xff1a;乔中沛&#xff08;伊灵&#xff09; 背景 随着万物互联场景的逐渐普及&#xff0c;边缘设备的算力也不断增强&#xff0c;如何借助云计算的优势满足复杂多样化的边缘应用场景&#xff0c;让云原生技术延伸到端和边缘成为了新的技术挑战&#xff0c;“云边协…

RNA-seq 详细教程:样本质控(6)

学习目标 了解计数数据变换方法的重要性了解 PCA (principal component analysis)了解如何使用 PCA 和层次聚类评估样本质量1. 质控 DESeq2 工作流程的下一步是 QC&#xff0c;其中包括样本和基因程度上&#xff0c;以对计数数据执行 QC 检查&#xff0c;以帮助我们确保样本或重…

[附源码]Python计算机毕业设计Django右脑开发教育课程管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

iOS现有APP上架流程​

一. 登录App Store Connect​ 1.登录App Store Connect(apple.com)账号密码登录​ 2.点击“我的App”-->”选中升级的APP”-->创建新的APP版本号​ 输入版本的升级内容--》然后点击右上角的“存储”按钮&#xff0c;保存本次修改。​ 上传更新App Store安装包​ Xcode-…

【Rust日报】2022-12-07 测量 Rust 中 HashMap 的开销

测量 Rust 中 HashMap 的开销在处理将大量数据放入 HashMap的项目时&#xff0c;作者开始注意到 HashMap 占用了大量内存并对最小内存使用量进行了粗略计算&#xff0c;得到的常驻内存是预期的两倍多。我们都知道 HashMaps 以空间换取时间。通过使用更多空间&#xff0c;我们能…

Apache HTTP 两个路径穿越漏洞复现

目录 Apache HTTP Server 2.4.49 路径穿越漏洞&#xff08;CVE-2021-41773&#xff09; 漏洞环境&#xff1a; 漏洞复现&#xff1a; 漏洞复现成功&#xff01; Apache HTTP Server 2.4.50 路径穿越漏洞&#xff08;CVE-2021-42013&#xff09; 漏洞复现分析&#xff1a; 漏…

React - Hooks 使用(函数组件中使用 React 特性)

React - Hooks 使用&#xff08;函数组件中使用 React 特性&#xff09;一. 为什么要使用 HOOKS&#xff1f;二. HOOKS 概念三. HOOKS 用法1. useState1.1 参数及返回值1.2 setState 两种写法1.3 setState 示例2. useEffect2.1 useEffect 实例3. useRef3.1 useRef 实例四. 一个…

R语言中的偏最小二乘回归PLS-DA

主成分回归&#xff08;PCR&#xff09;的方法 本质上是使用第一个方法的普通最小二乘&#xff08;OLS&#xff09;拟合来自预测变量的主成分&#xff08;PC&#xff09;。这带来许多优点&#xff1a; 预测变量的数量实际上没有限制。 相关的预测变量不会破坏回归拟合。 但是…

Letbook Cookbook题单——数组4

Letbook Cookbook题单——数组4 59. 螺旋矩阵 II 难度中等 给你一个正整数 n &#xff0c;生成一个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; [外链图片转存失败,源站可能有防盗链机制,建议将图片保…

毕业设计-基于大数据的PM2.5浓度预测的研究-python

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

Excel 函数大全之TRANSPOSE function

TRANSPOSE function 有时您需要切换或旋转单元格。您可以通过复制、粘贴和使用转置选项来完成此操作。但是这样做会产生重复的数据。如果您不想这样,您可以使用 TRANSPOSE 函数键入公式。例如,在下图中,公式=TRANSPOSE(A1:B4)将单元格 A1 到 B4 水平排列。 注意: 如果您有…