Redis实现附件店肆

[复制链接]
发表于 2025-9-23 05:34:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
Geospatial
焦点操作
  1. // 添加店铺数据预热操作,GEOADD key 经度 纬度 member
  2. stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString());
  3. ​
  4. // 具体查询,GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE
  5. GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo()
  6.                .search(
  7.                        key,
  8.                        GeoReference.fromCoordinate(x, y),// 圆心
  9.                        new Distance(5000),//距离圆心的距离
  10.                       RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end) //
  11.                );
复制代码
做数据预热:将商户信息添加到Redis里才华查到附件商户信息,每个商户包罗店肆id、经纬度 x , y。由于前端是按类型查询一群店肆信息的,所以要将同一类型的商户添加到同一个组里。
  1. void loadShopData() {
  2.    // 1.查询店铺信息
  3.    List<Shop> list = shopService.list();
  4.    // 2.把店铺分组,按照typeId分组,typeId一致的放到一个集合
  5.    Map<Long, List<Shop>> map = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
  6.    // 3.分批完成写入Redis
  7.    for (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {
  8.        // 3.1.获取类型id
  9.        Long typeId = entry.getKey();
  10.        String key = SHOP_GEO_KEY + typeId;
  11.        // 3.2.获取同类型的店铺的集合
  12.        List<Shop> value = entry.getValue();
  13.        List<RedisGeoCommands.GeoLocation<String>> locations = new ArrayList<>(value.size());
  14.        // 3.3.写入redis GEOADD key 经度 纬度 member
  15.        for (Shop shop : value) {
  16.            // stringRedisTemplate.opsForGeo().add(key, new Point(shop.getX(), shop.getY()), shop.getId().toString());
  17.            locations.add(new RedisGeoCommands.GeoLocation<>(
  18.                    shop.getId().toString(),
  19.                    new Point(shop.getX(), shop.getY())
  20.            ));
  21.        }
  22.        stringRedisTemplate.opsForGeo().add(key, locations);
  23.    }
  24. }
复制代码
依靠
  1. <dependency>
  2.    <groupId>org.springframework.boot</groupId>
  3.    <artifactId>
  4.        spring-boot-starter-data-redis
  5.    </artifactId>
  6.    <exclusions>
  7.        <exclusion>
  8.            <artifactId>spring-data-redis</artifactId>
  9.            <groupId>org.springframework.data</groupId>
  10.        </exclusion>
  11.        <exclusion>
  12.            <artifactId>lettuce-core</artifactId>
  13.            <groupId>io.lettuce</groupId>
  14.        </exclusion>
  15.    </exclusions>
  16. </dependency>
  17. <dependency>
  18.    <groupId>org.springframework.data</groupId>
  19.    <artifactId>spring-data-redis</artifactId>
  20.    <version>2.6.2</version>
  21. </dependency>
  22. <dependency>
  23.    <groupId>io.lettuce</groupId>
  24.    <artifactId>lettuce-core</artifactId>
  25.    <version>6.1.6.RELEASE</version>
  26. </dependency>
复制代码
ShopController
  1. @GetMapping("/of/type")
  2. public Result queryShopByType(
  3.        @RequestParam("typeId") Integer typeId,
  4.        @RequestParam(value = "current", defaultValue = "1") Integer current,
  5.        @RequestParam(value = "x", required = false) Double x,
  6.        @RequestParam(value = "y", required = false) Double y
  7. ) {
  8.   return shopService.queryShopByType(typeId, current, x, y);
  9. }
复制代码
ShopServiceImpl
  1. @Override
  2.    public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
  3.        // 1.判断是否需要根据坐标查询
  4.        if (x == null || y == null) {
  5.            // 不需要坐标查询,按数据库查询
  6.            Page<Shop> page = query()
  7.                    .eq("type_id", typeId)
  8.                    .page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
  9.            // 返回数据
  10.            return Result.ok(page.getRecords());
  11.        }
  12. ​
  13.        // 2.计算分页参数
  14.        int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;
  15.        int end = current * SystemConstants.DEFAULT_PAGE_SIZE;
  16. ​
  17.        // 3.查询redis、按照距离排序、分页。结果:shopId、distance
  18.        String key = SHOP_GEO_KEY + typeId;
  19.        GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo() // GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE
  20.                .search(
  21.                        key,
  22.                        GeoReference.fromCoordinate(x, y),
  23.                        new Distance(5000),
  24.                        RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end) //这里是从第一条到结束,所以要截取需要的数据返回
  25.                );
  26.        // 4.解析出id
  27.        if (results == null) {
  28.            return Result.ok(Collections.emptyList());
  29.        }
  30.        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();
  31.        if (list.size() <= from) {
  32.            // 没有下一页了,结束
  33.            return Result.ok(Collections.emptyList());
  34.        }
  35.        // 4.1.截取 from ~ end的部分
  36.        List<Long> ids = new ArrayList<>(list.size());
  37.        Map<String, Distance> distanceMap = new HashMap<>(list.size());
  38.        
  39.        list.stream().skip(from).forEach(result -> {
  40.            // 4.2.获取店铺id
  41.            String shopIdStr = result.getContent().getName();
  42.            ids.add(Long.valueOf(shopIdStr));
  43.            // 4.3.获取距离
  44.            Distance distance = result.getDistance();
  45.            distanceMap.put(shopIdStr, distance);
  46.        });
  47.        // 5.根据id查询Shop
  48.        String idStr = StrUtil.join(",", ids);
  49.        List<Shop> shops = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
  50.        for (Shop shop : shops) {
  51.            shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
  52.        }
  53.        // 6.返回
  54.        return Result.ok(shops);
  55.    }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表