报告模块重构

This commit is contained in:
attiya 2025-11-17 10:10:10 +08:00
parent c0b9515088
commit 2d072b01ff
12 changed files with 26 additions and 303 deletions

View File

@ -1,15 +1,9 @@
package com.cdzy.operations.utils; package com.cdzy.operations.utils;
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.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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -24,131 +18,12 @@ public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
private final String geoKey="ebike_geo";
@Autowired @Autowired
public RedisUtil(RedisTemplate<String, Object> redisTemplate) { public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
this.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<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;
}
/**
* 判断点是否在多边形内
* @param point 待判断点
* @param polygon 多边形顶点
* @return 是否在多边形内
*/
public static boolean isPointInPolygon(Point point, List<Point> polygon) {
double x = point.getX();
double y = point.getY();
boolean inside = false;
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
double xi = polygon.get(i).getX();
double yi = polygon.get(i).getY();
double xj = polygon.get(j).getX();
double yj = polygon.get(j).getY();
boolean intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
/**
* 删除 Redis
*
*/
public void deleteGeoKey() {
redisTemplate.delete(geoKey);
}
/** /**
* 设置过期时间 * 设置过期时间
* @param key * @param key

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport; package com.cdzy.report;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.component; package com.cdzy.report.component;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.HealthIndicator;

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.component; package com.cdzy.report.component;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;

View File

@ -1,12 +1,12 @@
package com.cdzy.ebikereport.component; package com.cdzy.report.component;
import com.cdzy.common.model.dto.EbikeTracking; import com.cdzy.common.model.dto.EbikeTracking;
import com.cdzy.common.model.dto.ResGPSDto; import com.cdzy.common.model.dto.ResGPSDto;
import com.cdzy.common.utils.CoordinateUtil; import com.cdzy.common.utils.CoordinateUtil;
import com.cdzy.ebikereport.enums.BitSwitch; import com.cdzy.report.enums.BitSwitch;
import com.cdzy.ebikereport.utils.BinaryUtil; import com.cdzy.report.utils.BinaryUtil;
import com.cdzy.ebikereport.utils.RedisUtil; import com.cdzy.report.utils.RedisUtil;
import com.ebike.feign.clients.OperationsFeignClient; import com.ebike.feign.clients.OperationsFeignClient;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.config; package com.cdzy.report.config;
import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.config; package com.cdzy.report.config;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.enums; package com.cdzy.report.enums;
/** /**
* @author attiya * @author attiya

View File

@ -1,4 +1,4 @@
package com.cdzy.ebikereport.utils; package com.cdzy.report.utils;
/** /**
* @author attiya * @author attiya

View File

@ -1,15 +1,9 @@
package com.cdzy.ebikereport.utils; package com.cdzy.report.utils;
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.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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -24,131 +18,12 @@ public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
private final String geoKey="ebike_geo";
@Autowired @Autowired
public RedisUtil(RedisTemplate<String, Object> redisTemplate) { public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
this.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<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;
}
/**
* 判断点是否在多边形内
* @param point 待判断点
* @param polygon 多边形顶点
* @return 是否在多边形内
*/
public static boolean isPointInPolygon(Point point, List<Point> polygon) {
double x = point.getX();
double y = point.getY();
boolean inside = false;
for (int i = 0, j = polygon.size() - 1; i < polygon.size(); j = i++) {
double xi = polygon.get(i).getX();
double yi = polygon.get(i).getY();
double xj = polygon.get(j).getX();
double yj = polygon.get(j).getY();
boolean intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
}
/**
* 删除 Redis
*
*/
public void deleteGeoKey() {
redisTemplate.delete(geoKey);
}
/** /**
* 设置过期时间 * 设置过期时间
* @param key * @param key

View File

@ -1,41 +0,0 @@
package com.cdzy.ebikereport;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.model.EbikeTracking;
import com.cdzy.common.model.ResGPSDto;
import com.cdzy.common.utils.CoordinateUtil;
import com.cdzy.ebikereport.enums.BitSwitch;
import com.cdzy.ebikereport.utils.BinaryUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.geo.Point;
@SpringBootTest
class EbikeReportApplicationTests {
@Test
void contextLoads() {
Integer number = 131082;
String binary = BinaryUtil.to32BitBinary(number);
binary = new StringBuilder(binary).reverse().toString();
System.out.println(binary);
char helmet = binary.charAt(BitSwitch.IS_HELMET_EXIT);
char acc = binary.charAt(BitSwitch.ACC_ON);
System.out.println(acc);
char wheelLocked = binary.charAt(BitSwitch.IS_WHEEL_LOCKED);
char setLocked = binary.charAt(BitSwitch.IS_SEAT_LOCKED);
char isHelmetLocked = binary.charAt(BitSwitch.IS_HELMET_LOCKED);
char isWheelSpin = binary.charAt(BitSwitch.IS_WHEEL_SPIN);
char isMoving = binary.charAt(BitSwitch.IS_MOVING);
ResGPSDto resGpsDto = new ResGPSDto();
resGpsDto.setHelmetExit(helmet);
resGpsDto.setAccOn(acc);
resGpsDto.setWheelLocked(wheelLocked);
resGpsDto.setSeatLocked(setLocked);
resGpsDto.setIsHelmetLocked(isHelmetLocked);
resGpsDto.setIsWheelSpin(isWheelSpin);
resGpsDto.setIsMoving(isMoving);
}
}

View File

@ -0,0 +1,14 @@
package com.cdzy.report;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class EbikeReportApplicationTests {
@Test
void contextLoads() {
}
}