package com.cdzy.ebikemaintenance.utils; import com.cdzy.common.model.ResGPSDto; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Polygon; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.*; import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * @author attiya * @since 2025-03-20 */ @Component public class RedisUtil { private final RedisTemplate redisTemplate; private final String geoKey="ebike_geo"; @Autowired public RedisUtil(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } /* ------------------- key 相关操作 ------------------ */ /** * 添加地理位置 * * @param point 经纬度 * @param member 成员名称 */ public void addLocation(Point point, String member) { redisTemplate.opsForGeo().add(geoKey, point, member); } /** * 查询指定范围内的成员 * * @param center 中心点 * @param radius 半径(单位:公里) * @return 范围内的成员列表 */ public List findNearbyMembers(Point center, double radius) { Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.KILOMETERS); Circle circle = new Circle(center, distance); GeoResults> results = redisTemplate.opsForGeo() .radius(geoKey, circle); return results.getContent().stream() .map(geoLocation -> geoLocation.getContent().getName().toString()) .toList(); } /** * 多边形查询 * @param polygonPoints 边界点 * @return 成员列表 */ public List searchByPolygon( List polygonPoints ) { // 1. 构造多边形 GeometryFactory factory = new GeometryFactory(); Coordinate[] coordinates = polygonPoints.stream() .map(p -> new Coordinate(p.getX(), p.getY())) .toArray(Coordinate[]::new); Polygon polygon = factory.createPolygon(coordinates); // 2. 计算最小外接圆 Point center = calculateBoundingCircleCenter(polygonPoints); double radius = calculateMaxRadius(polygonPoints, center); // 3. 查询圆内所有点 GeoResults> results = redisTemplate.opsForGeo() .radius(geoKey, new Circle(center, new Distance(radius, Metrics.KILOMETERS)), RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs() .includeCoordinates()); // 4. 过滤多边形内的点 List matches = new ArrayList<>(); for (GeoResult> result : results) { Point point = result.getContent().getPoint(); if (polygon.contains(factory.createPoint( new Coordinate(point.getX(), point.getY())))) { matches.add(result.getContent().getName().toString()); } } return matches; } // 计算外接圆中心(多边形顶点平均值) private Point calculateBoundingCircleCenter(List points) { double sumX = 0, sumY = 0; for (Point p : points) { sumX += p.getX(); sumY += p.getY(); } return new Point(sumX / points.size(), sumY / points.size()); } // 计算最大半径 private double calculateMaxRadius(List points, Point center) { return points.stream() .mapToDouble(p -> Math.sqrt( Math.pow(p.getX() - center.getX(), 2) + Math.pow(p.getY() - center.getY(), 2))) .max().orElse(0)*100; } /** * 删除 Redis 键 * */ public void deleteGeoKey() { redisTemplate.delete(geoKey); } /** * 设置过期时间 * @param key 键 * @param timeout 超时时间 * @param unit 时间单位 */ public Boolean expire(String key, long timeout, TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 获取过期时间 * @param key 键 * @param unit 时间单位 */ public Long getExpire(String key, TimeUnit unit) { return redisTemplate.getExpire(key, unit); } /** * 判断key是否存在 * @param key 键 */ public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 删除key * @param key 键 */ public Boolean delete(String key) { return redisTemplate.delete(key); } /* ------------------- String 相关操作 ------------------ */ /** * 设置键值对 * @param key 键 * @param value 值 */ public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } /** * 设置键值对并设置过期时间 * @param key 键 * @param value 值 * @param timeout 过期时间 * @param unit 时间单位 */ public void set(String key, Object value, long timeout, TimeUnit unit) { redisTemplate.opsForValue().set(key, value, timeout, unit); } /** * 获取值 * @param key 键 */ public Object get(String key) { return redisTemplate.opsForValue().get(key); } /** * 批量获取值 * @param key 键列表 */ public List getAll(List key) { return redisTemplate.opsForValue().multiGet(key); } /** * 自增操作(增量=1) * @param key 键 */ public Long increment(String key) { return redisTemplate.opsForValue().increment(key); } /** * 自增操作(指定增量) * @param key 键 * @param delta 增量 */ public Long increment(String key, long delta) { return redisTemplate.opsForValue().increment(key, delta); } /* ------------------- Hash 相关操作 ------------------ */ /** * 设置Hash键值对 * @param key 键 * @param hashKey Hash键 * @param value 值 */ public void hSet(String key, String hashKey, Object value) { redisTemplate.opsForHash().put(key, hashKey, value); } /** * 批量设置Hash键值对 * @param key 键 * @param map 多个Hash键值对 */ public void hSetAll(String key, Map map) { redisTemplate.opsForHash().putAll(key, map); } /** * 获取Hash值 * @param key 键 * @param hashKey Hash键 */ public Object hGet(String key, String hashKey) { return redisTemplate.opsForHash().get(key, hashKey); } /** * 获取所有Hash键值对 * @param key 键 */ public Map hGetAll(String key) { return redisTemplate.opsForHash().entries(key); } /** * 删除Hash键 * @param key 键 * @param hashKeys Hash键集合 */ public Long hDelete(String key, Object... hashKeys) { return redisTemplate.opsForHash().delete(key, hashKeys); } /* ------------------- List 相关操作 ------------------ */ /** * 左推入元素 * @param key 键 * @param value 值 */ public Long lPush(String key, Object value) { return redisTemplate.opsForList().leftPush(key, value); } /** * 右推入元素 * @param key 键 * @param value 值 */ public Long rPush(String key, Object value) { return redisTemplate.opsForList().rightPush(key, value); } /** * 获取列表范围 * @param key 键 * @param start 开始索引 * @param end 结束索引 */ public List lRange(String key, long start, long end) { return redisTemplate.opsForList().range(key, start, end); } /* ------------------- Set 相关操作 ------------------ */ /** * 添加集合元素 * @param key 键 * @param values 值数组 */ public Long sAdd(String key, Object... values) { return redisTemplate.opsForSet().add(key, values); } /** * 获取集合所有元素 * @param key 键 */ public Set sMembers(String key) { return redisTemplate.opsForSet().members(key); } /* ------------------- ZSet 相关操作 ------------------ */ /** * 添加有序集合元素 * @param key 键 * @param value 值 * @param score 分数 */ public Boolean zAdd(String key, Object value, double score) { return redisTemplate.opsForZSet().add(key, value, score); } /** * 获取有序集合范围 * @param key 键 * @param start 开始索引 * @param end 结束索引 */ public Set zRange(String key, long start, long end) { return redisTemplate.opsForZSet().range(key, start, end); } /* ------------------- 其他操作 ------------------ */ /** * 获取匹配的键 * @param pattern 匹配模式 */ public Set keys(String pattern) { return redisTemplate.keys(pattern); } /** * 分布式锁:尝试获取锁 * @param key 锁键 * @param value 锁值 * @param timeout 超时时间 * @param unit 时间单位 */ public Boolean tryLock(String key, Object value, long timeout, TimeUnit unit) { return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit); } /** * 释放锁 * @param key 锁键 */ public Boolean releaseLock(String key) { return redisTemplate.delete(key); } }