跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Java大前端java算法

黑马点评商铺分页查询异常排查与修复

针对黑马点评项目中商铺列表滚动分页失效及首页重复查询问题,定位到后端 Redis GEO 分页逻辑与默认页大小配置不匹配。通过调整 SystemConstants.DEFAULT_PAGE_SIZE 至合理数值并优化 Stream 流式分页处理,解决了数据偏移异常,实现了按距离排序的准确分页展示。

邪神洛基发布于 2026/4/10更新于 2026/7/2934 浏览
黑马点评商铺分页查询异常排查与修复

黑马点评商铺分页查询异常排查与修复

在开发过程中遇到了一个棘手的前端交互问题。页面中选择美食类别后往下翻,无法自动滚动分页查询所有的美食店铺数据,前端滚动没反应。

文章配图

还有个比较诡异的点:前端点击'距离'排序后,滚动查询第一页时数据被查询了两次,后续翻页则正常。如下图所示。

排查许久后,定位到根源在于后端分页配置的大小设定。我的后端代码如下:

Controller 层

/**
 * 根据商铺类型分页查询商铺信息
 * @param typeId 商铺类型
 * @param current 页码
 * @param x 经度
 * @param y 纬度
 * @return 商铺列表
 */
@GetMapping("/of/type")
public Result queryShopByType(
        @RequestParam("typeId") Integer typeId,
        @RequestParam(value = "current", defaultValue = "1") Integer current,
        @RequestParam("x") Double x,
        @RequestParam("y") Double y
) {
    // 调用 Service 层方法(修正方法名驼峰规范)
    return shopService.queryShopByType(typeId, current, x, y);
}

ServiceImpl 层

@Override
public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
    if (x == null || y == null) {
        // 直接返回对应类型的店铺就行了
        Page<Shop> page = query()
                .eq("type_id", typeId)
                .page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
        return Result.ok(page.getRecords());
    }

    int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;
    int end = current * SystemConstants.DEFAULT_PAGE_SIZE;
    String key = "geo:shop:type:" + typeId;

    // 构造 5000 米的距离对象(核心:指定米为单位,5000m)
    Distance distance = new Distance(5000, Metrics.METERS);

    // 完整的 GEO 圆形区域查询(补全所有参数)
    GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = stringRedisTemplate.opsForGeo()
            .search(key,
                    GeoReference.fromCoordinate(new Point(x, y)),
                    distance,
                    RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                            .sortAscending() // 按距离从近到远排序(附近商户必备)
                            .limit(end) // 预查足够数据,为后续分页准备
                            .includeDistance() // 核心:让 Redis 返回每个元素到圆心的距离
                            .includeCoordinates() // 预查数据,避免分页漏条
            );

    // 判空:geoResults 为空或无内容,直接返回空列表
    if (geoResults == null || geoResults.getContent().isEmpty()) {
        return Result.ok(Collections.emptyList());
    }

    // 核心:Stream 分页(skip+limit)并接收结果,提取【商铺 ID+距离】
    List<GeoResult<RedisGeoCommands.GeoLocation<String>>> pageGeoList = geoResults.getContent().stream()
            .skip(from) // 跳过前 from 条,实现分页
            .limit(SystemConstants.DEFAULT_PAGE_SIZE) // 截取分页条数(一页的数量)
            .collect(Collectors.toList()); // 必须 collect 接收结果,否则跳过不生效

    // 提取商铺 ID(批量查库,替代循环单查,提升性能 10 倍+)
    List<Long> shopIds = pageGeoList.stream()
            .map(geoResult -> Long.valueOf(geoResult.getContent().getName()))
            .collect(Collectors.toList());

    if (shopIds.isEmpty()) {
        return Result.ok(Collections.emptyList());
    }

    String shopIdstr = StringUtil.join(shopIds, ",");

    // 批量查询商铺详情(MyBatis-Plus 批量查,避免循环 eq 单查)
    List<Shop> shopList = query().in("id", shopIds).last(("ORDER BY FIELD(id, " + shopIdstr + "))).list();

    // 给商铺赋值距离(并保证 shopList 顺序和 pageGeoList 一致)
    for (int i = 0; i < pageGeoList.size(); i++) {
        GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult = pageGeoList.get(i);
        Shop shop = shopList.get(i);
        // 距离转 Double,加非空判断(防止空指针)
        Double distValue = geoResult.getDistance().getValue();
        shop.setDistance(distValue);
    }

    return Result.ok(shopList);
}

将 DEFAULT_PAGE_SIZE 的大小改为 5 以上即可解决该问题。这主要是因为 Redis GEO 搜索返回的数据量如果小于预期,会导致分页偏移计算出现偏差,适当增大初始查询范围能覆盖更多潜在数据,从而保证分页逻辑稳定。

目录

  1. 黑马点评商铺分页查询异常排查与修复
  2. Controller 层
  3. ServiceImpl 层
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • MCP Server 实战:Excel 数据转可视化 HTML 报告
  • 2026 年 3 月 18 日 AI 产业前沿动态:算力、智能体与生态变革
  • 百度文心 5.0 发布:2.4 万亿参数与原生全模态解析
  • 使用 Ollama 本地部署 Llama 3.1 大模型指南
  • 前端 rem 自适应布局方案详解与实战避坑
  • CAS 原理与 Java 原子类实战
  • Yuan2.0 数据预处理
  • OpenClaw 开源机器人实现空间记忆,具身智能迎来新突破
  • Grok 开源发布:程序员在大模型时代的技术机遇
  • Open WebUI MCPo 技术解析:MCP 工具转 OpenAPI 代理方案
  • 高速 ADC 串行 LVDS 数据捕获与接口设计
  • Flutter TabBar 高级标签系统与导航交互优化实现
  • 基于 Open-AutoGLM 的手机 AI Agent 自动化部署指南
  • 2024-2025 主流开源 TTS 模型综合对比分析
  • C++ 手写 Web 服务器:基于 JSON 与 HTTP 协议的实现
  • FUXA:基于 Web 的 HMI-SCADA-Dashboard 可视化组态平台
  • Spring Cloud Nacos 实战指南:服务注册、配置管理与负载均衡
  • 降低论文 AI 检测率的 10 条指令与工具实测
  • Lostlife2.0 整合 LLama-Factory 引擎重塑 NPC 对话逻辑
  • Beautiful Hugo 上手:从零搭建静态博客

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online