JavaRedis

使用Redis实现附近的人的查询功能 - 例子记录

2022-08-30  本文已影响0人  右耳菌

1. 数据结构 - GEO

GEO 3.2版本开始对GEO(地理位置)的支持
使用场景:LBS应用开发

常用命令

  1. GEOADD
    增加地理位置的坐标,可以批量添加地理位置
  2. GEODIST
    获取两个地理位置的距离
  3. GEOHASH
    获取某个地理位置的geohash值
  4. GEOPOS
    获取指定位置的坐标,可以批量获取多个地理位置的坐标
  5. GEORADIUS
    根据给定地理位置坐标获取指定范围内的地理位置集合(注意:该命令的中心点由输入的经度和纬度决定)
  6. GEORADIUSBYMEMBER
    根据给定成员的位置获取指定范围内的位置信息集合(注意:该命令的中心点是由给定的位置元素决定)

2. 例子

2.1 创建SpringBoot项目
  1. 修改 pom.xml
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.9.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
  1. 修改 application.properties
spring.redis.host=192.168.1.7
spring.redis.port=6379
2.2 创建AppConfig.java(spring配置类)
package cn.lazyfennec.redisnearbydemo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/8/30 23:14
 */
@Configuration //
public class AppConfig {

    @Value("${spring.redis.host}") // springel
    private String host;

    @Value("${spring.redis.port}")
    int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
        redisConnectionFactory.afterPropertiesSet();
        return redisConnectionFactory;
    }


    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8); // key -- string
        redisTemplate.setConnectionFactory(redisConnectionFactory); //
        // redisTemplate.setValueSerializer();

        // 必须执行这个函数,这个函数的作用是初始化参数和初识化工作
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
2.3 创建相关的service
package cn.lazyfennec.redisnearbydemo.service;

import org.springframework.data.geo.Point;

public interface ILBSService {

    void save(Point point, String userId);

    Object near(Point point);

}
package cn.lazyfennec.redisnearbydemo.service.impl;

import cn.lazyfennec.redisnearbydemo.service.ILBSService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/8/30 23:16
 */
@Service
public class LBSServiceImpl implements ILBSService {
    private static final String GEO_KEY = "user_geo";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 上传位置
     */
    public void save(Point point, String userId) {
        redisTemplate.opsForGeo().add(GEO_KEY, new RedisGeoCommands.GeoLocation<>(userId, point));
    }

    /**
     * 附近的人
     *
     * @param point 用户自己的位置
     */
    public GeoResults<RedisGeoCommands.GeoLocation> near(Point point) {
        // 半径 3000米
        Distance distance = new Distance(3000, RedisGeoCommands.DistanceUnit.METERS);
        Circle circle = new Circle(point, distance);
        // 附近5个人 -- 业务需求
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(5);
        GeoResults<RedisGeoCommands.GeoLocation> geoResults = redisTemplate.opsForGeo().radius(GEO_KEY, circle, geoRadiusCommandArgs);
        return geoResults;
    }
}
2.4 创建LBSController
package cn.lazyfennec.redisnearbydemo.controller;

import cn.lazyfennec.redisnearbydemo.service.ILBSService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/8/30 23:14
 */
@RestController
public class LBSController {

    @Autowired
    ILBSService lbsService;

    /**
     * 上传位置
     *
     * @param userId    从登录信息获取。。此处示例作为参数
     * @param latitude  纬度
     * @param longitude 经度
     */
    @RequestMapping("/geo/save")
    public void save(String userId, String longitude, String latitude) {
        Point point = new Point(Double.valueOf(longitude), Double.valueOf(latitude));
        lbsService.save(point, userId);
    }

    @RequestMapping("/geo/near")
    public Object near(String longitude, String latitude) {
        Point point = new Point(Double.valueOf(longitude), Double.valueOf(latitude));
        return lbsService.near(point);
    }
}
2.5 创建 static/GEOTest.html
<!-- saved from url=(0022)http://127.0.0.1:8080/ -->
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>附近的人</title></head>
<body>
<script type="text/javascript">
    // 1. 模拟保存用户位置
    function save(userId, longitude, latitude) {
        var ajax = new XMLHttpRequest();
        ajax.open('get', '/geo/save?userId=' + userId + "&longitude=" + longitude + "&latitude=" + latitude);
        ajax.send();
        ajax.onreadystatechange = function () {
            // 后台上报位置,无需任何返回
            console.log(ajax.readyState + ">>>" + ajax.status);
        }
    }

    // 2. 查询附近的人
    function near(userId, longitude, latitude) {
        var ajax = new XMLHttpRequest();
        ajax.open('get', '/geo/near?userId=' + userId + "&longitude=" + longitude + "&latitude=" + latitude);
        ajax.send();
        ajax.onreadystatechange = function () {
            if (ajax.readyState == 4 && ajax.status == 200) {
                var result = JSON.stringify(JSON.parse(ajax.responseText), null, 4);  // 缩进4个空格 ;
                var ta = document.getElementById('responseText');
                ta.value = result;
            }
        }
    }

</script>
<form onsubmit="return false;">
    <h3>------经纬度:(120.197246,30.193334)-------</h3>
    <input type="text" name="longitude" value="经度"/>
    <input type="text" name="latitude" value="纬度"/>
    <input type="text" name="userId" value="用户ID"/>
    <input type="button" value="模拟用户"
           onclick="save(this.form.userId.value,this.form.longitude.value, this.form.latitude.value)"/>
    <input type="button" value="搜索附近的人"
           onclick="near(this.form.userId.value,this.form.longitude.value, this.form.latitude.value)"/>

    <h3>------3km 附近的人列表-------</h3>
    <textarea id="responseText" style="width:500px;height:600px;"></textarea>
</form>
</body>
</html>

3. 测试页面

上一篇下一篇

猜你喜欢

热点阅读