CollisionAvoidanceSystem/src/main/java/com/dongni/collisionavoidance/common/service/VehicleLocationService.java
Tian jianyong 05e080cb30 1. 创建车辆位置PostGIS实体类(VehicleLocation、Aircraft、VehicleTrajectory)
2. 创建机场区域PostGIS实体类(AirportArea)
3. 创建数据库迁移脚本(表结构、索引、分区)
4. 实现车辆位置Repository接口
5. 实现机场区域Repository接口
6. 创建PostGIS车辆服务(PostGISVehicleService)
7. 创建PostGIS区域服务(PostGISAreaService)
8. 创建统一空间查询服务(SpatialQueryService)
9. 实现区域配置导入工具(YAML到数据库)
10. 重构DataCollectorService(移除内存存储)
11. 重构AirportAreaService(基于数据库查询)
12. 移除MovingObjectRepository和相关内存存储代码
13. 移除AirportAreasProperties和YAML配置加载
14. 实现Redis缓存策略
15. 数据库连接池和性能优化配置
16. 创建单元测试和集成测试
2025-06-10 18:45:54 +08:00

288 lines
11 KiB
Java

package com.dongni.collisionavoidance.common.service;
import com.dongni.collisionavoidance.common.model.spatial.VehicleLocation;
import com.dongni.collisionavoidance.common.model.repository.VehicleLocationRepository;
import com.dongni.collisionavoidance.common.model.MovingObjectType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* 车辆位置服务类 - 基于PostGIS的空间数据管理
* 提供车辆位置的保存、查询、空间分析等功能
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class VehicleLocationService {
private final VehicleLocationRepository vehicleLocationRepository;
private final GeometryFactory geometryFactory = new GeometryFactory();
/**
* 保存车辆位置信息
*/
@Transactional
public VehicleLocation saveVehicleLocation(VehicleLocation vehicleLocation) {
try {
VehicleLocation saved = vehicleLocationRepository.save(vehicleLocation);
log.debug("保存车辆位置: vehicleId={}, location=({}, {})",
saved.getVehicleId(),
saved.getLocation().getX(),
saved.getLocation().getY());
return saved;
} catch (Exception e) {
log.error("保存车辆位置失败: vehicleId={}", vehicleLocation.getVehicleId(), e);
throw new RuntimeException("保存车辆位置失败", e);
}
}
/**
* 批量保存车辆位置信息
*/
@Transactional
public List<VehicleLocation> saveVehicleLocations(List<VehicleLocation> vehicleLocations) {
try {
List<VehicleLocation> saved = vehicleLocationRepository.saveAll(vehicleLocations);
log.info("批量保存车辆位置: 数量={}", saved.size());
return saved;
} catch (Exception e) {
log.error("批量保存车辆位置失败: 数量={}", vehicleLocations.size(), e);
throw new RuntimeException("批量保存车辆位置失败", e);
}
}
/**
* 创建车辆位置记录
*/
public VehicleLocation createVehicleLocation(String vehicleId, MovingObjectType vehicleType,
double longitude, double latitude,
Double altitude, Double heading, Double speed) {
Point location = geometryFactory.createPoint(new Coordinate(longitude, latitude));
location.setSRID(4326); // 设置WGS84坐标系
VehicleLocation vehicleLocation = new VehicleLocation();
vehicleLocation.setVehicleId(vehicleId);
vehicleLocation.setVehicleType(vehicleType);
vehicleLocation.setLocation(location);
vehicleLocation.setAltitude(altitude);
vehicleLocation.setHeading(heading);
vehicleLocation.setSpeed(speed);
vehicleLocation.setTimestamp(LocalDateTime.now());
return vehicleLocation;
}
/**
* 根据车辆ID获取最新位置
*/
public Optional<VehicleLocation> getLatestVehicleLocation(String vehicleId) {
try {
return vehicleLocationRepository.findLatestByVehicleId(vehicleId);
} catch (Exception e) {
log.error("获取车辆最新位置失败: vehicleId={}", vehicleId, e);
return Optional.empty();
}
}
/**
* 根据车辆类型获取活跃车辆
*/
public List<VehicleLocation> getActiveVehiclesByType(String vehicleType, int minutesBack) {
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findActiveByVehicleType(vehicleType, since);
} catch (Exception e) {
log.error("获取活跃车辆失败: vehicleType={}, minutesBack={}", vehicleType, minutesBack, e);
return List.of();
}
}
/**
* 空间查询:获取指定半径范围内的车辆
*/
public List<VehicleLocation> getVehiclesWithinRadius(double longitude, double latitude,
double radiusMeters, int minutesBack) {
Point centerPoint = geometryFactory.createPoint(new Coordinate(longitude, latitude));
centerPoint.setSRID(4326);
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findVehiclesWithinRadius(centerPoint, radiusMeters, since);
} catch (Exception e) {
log.error("半径查询失败: center=({}, {}), radius={}m", longitude, latitude, radiusMeters, e);
return List.of();
}
}
/**
* 空间查询:获取指定区域内的车辆
*/
public List<VehicleLocation> getVehiclesInArea(String areaWkt, int minutesBack) {
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findVehiclesInArea(areaWkt, since);
} catch (Exception e) {
log.error("区域查询失败: areaWkt={}", areaWkt, e);
return List.of();
}
}
/**
* 获取车辆轨迹数据
*/
public List<VehicleLocation> getVehicleTrajectory(String vehicleId, LocalDateTime startTime, LocalDateTime endTime) {
try {
return vehicleLocationRepository.findVehicleTrajectory(vehicleId, startTime, endTime);
} catch (Exception e) {
log.error("获取车辆轨迹失败: vehicleId={}, 时间范围=[{}, {}]", vehicleId, startTime, endTime, e);
return List.of();
}
}
/**
* 获取指定高度范围内的车辆
*/
public List<VehicleLocation> getVehiclesByAltitudeRange(double minAltitude, double maxAltitude, int minutesBack) {
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findVehiclesByAltitudeRange(minAltitude, maxAltitude, since);
} catch (Exception e) {
log.error("高度范围查询失败: 高度范围=[{}, {}]", minAltitude, maxAltitude, e);
return List.of();
}
}
/**
* 获取高速移动的车辆
*/
public List<VehicleLocation> getHighSpeedVehicles(double speedThreshold, int minutesBack) {
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findHighSpeedVehicles(speedThreshold, since);
} catch (Exception e) {
log.error("高速车辆查询失败: speedThreshold={}", speedThreshold, e);
return List.of();
}
}
/**
* 获取最近的N个车辆
*/
public List<VehicleLocation> getNearestVehicles(double longitude, double latitude, int limit, int minutesBack) {
Point referencePoint = geometryFactory.createPoint(new Coordinate(longitude, latitude));
referencePoint.setSRID(4326);
LocalDateTime since = LocalDateTime.now().minusMinutes(minutesBack);
try {
return vehicleLocationRepository.findNearestVehicles(referencePoint, since, limit);
} catch (Exception e) {
log.error("最近车辆查询失败: reference=({}, {}), limit={}", longitude, latitude, limit, e);
return List.of();
}
}
/**
* 统计指定时间段内的唯一车辆数量
*/
public long countUniqueVehiclesInTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
try {
return vehicleLocationRepository.countUniqueVehiclesInTimeRange(startTime, endTime);
} catch (Exception e) {
log.error("车辆统计失败: 时间范围=[{}, {}]", startTime, endTime, e);
return 0;
}
}
/**
* 清理历史数据
*/
@Transactional
public int cleanupHistoricalData(LocalDateTime beforeTime) {
try {
int deletedCount = vehicleLocationRepository.deleteHistoricalData(beforeTime);
log.info("清理历史数据完成: 删除记录数={}, 清理时间点={}", deletedCount, beforeTime);
return deletedCount;
} catch (Exception e) {
log.error("清理历史数据失败: beforeTime={}", beforeTime, e);
throw new RuntimeException("清理历史数据失败", e);
}
}
/**
* 更新车辆位置 (如果存在则更新,否则创建新记录)
*/
@Transactional
public VehicleLocation updateOrCreateVehicleLocation(String vehicleId, MovingObjectType vehicleType,
double longitude, double latitude,
Double altitude, Double heading, Double speed) {
VehicleLocation vehicleLocation = createVehicleLocation(vehicleId, vehicleType,
longitude, latitude,
altitude, heading, speed);
vehicleLocation.setTimestamp(LocalDateTime.now());
return saveVehicleLocation(vehicleLocation);
}
/**
* 验证车辆位置数据的有效性
*/
public boolean isValidVehicleLocation(double longitude, double latitude, Double altitude, Double heading, Double speed) {
// 经度范围检查
if (longitude < -180 || longitude > 180) {
log.warn("无效的经度值: {}", longitude);
return false;
}
// 纬度范围检查
if (latitude < -90 || latitude > 90) {
log.warn("无效的纬度值: {}", latitude);
return false;
}
// 高度检查
if (altitude != null && (altitude < -1000 || altitude > 50000)) {
log.warn("无效的高度值: {}", altitude);
return false;
}
// 航向检查
if (heading != null && (heading < 0 || heading >= 360)) {
log.warn("无效的航向值: {}", heading);
return false;
}
// 速度检查
if (speed != null && (speed < 0 || speed > 1000)) {
log.warn("无效的速度值: {}", speed);
return false;
}
return true;
}
/**
* 根据车辆ID删除所有历史位置记录
*/
@Transactional
public void deleteVehicleLocations(String vehicleId) {
try {
vehicleLocationRepository.deleteAll(
vehicleLocationRepository.findVehicleTrajectory(vehicleId,
LocalDateTime.now().minusYears(10), LocalDateTime.now())
);
log.info("删除车辆位置记录: vehicleId={}", vehicleId);
} catch (Exception e) {
log.error("删除车辆位置记录失败: vehicleId={}", vehicleId, e);
throw new RuntimeException("删除车辆位置记录失败", e);
}
}
}