2025-07-31 16:30:34 +08:00

368 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<String, Object> redisTemplate;
private final String geoKey="ebike_geo";
@Autowired
public RedisUtil(RedisTemplate<String, Object> 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<String> findNearbyMembers(Point center, double radius) {
Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.KILOMETERS);
Circle circle = new Circle(center, distance);
GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo()
.radius(geoKey, circle);
return results.getContent().stream()
.map(geoLocation -> geoLocation.getContent().getName().toString())
.toList();
}
/**
* 多边形查询
* @param polygonPoints 边界点
* @return 成员列表
*/
public List<String> searchByPolygon( List<Point> 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<RedisGeoCommands.GeoLocation<Object>> results =
redisTemplate.opsForGeo()
.radius(geoKey,
new Circle(center, new Distance(radius, Metrics.KILOMETERS)),
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
.includeCoordinates());
// 4. 过滤多边形内的点
List<String> matches = new ArrayList<>();
for (GeoResult<RedisGeoCommands.GeoLocation<Object>> 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<Point> 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<Point> 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<Object> getAll(List<String> 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<String, Object> 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<Object, Object> 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<Object> 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<Object> 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<Object> zRange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/* ------------------- 其他操作 ------------------ */
/**
* 获取匹配的键
* @param pattern 匹配模式
*/
public Set<String> 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);
}
}