Remove Redis and optimize initialization code
This commit is contained in:
parent
27dfb2d878
commit
bff31311de
@ -0,0 +1,51 @@
|
||||
package com.zhangy.skyeye.cache;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 抽象类型缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/3 14:31
|
||||
*/
|
||||
public abstract class AbstractTypedCache {
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
protected AbstractTypedCache(Cache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
protected void put(String key, Object value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
protected <T> T get(String key, Class<T> type) {
|
||||
return cache.get(key, type);
|
||||
}
|
||||
|
||||
protected Object getRaw(String key) {
|
||||
Cache.ValueWrapper wrapper = cache.get(key);
|
||||
return wrapper == null ? null : wrapper.get();
|
||||
}
|
||||
|
||||
protected void evict(String key) {
|
||||
cache.evict(key);
|
||||
}
|
||||
|
||||
/** 获取原生 Caffeine Map,用于全量读取 */
|
||||
public Map<Object, Object> asMap() {
|
||||
Object nativeCache = cache.getNativeCache();
|
||||
if (nativeCache instanceof com.github.benmanes.caffeine.cache.Cache) {
|
||||
return ((com.github.benmanes.caffeine.cache.Cache<Object, Object>) nativeCache).asMap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Object getNativeCache() {
|
||||
return cache.getNativeCache();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
package com.zhangy.skyeye.cache.config;
|
||||
|
||||
import com.zhangy.skyeye.cache.publics.UserTokenTypedCache;
|
||||
import com.zhangy.skyeye.cache.sar.SarTypedCache;
|
||||
import com.zhangy.skyeye.cache.uav.UavTypedCache;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: Cache Bean 显式注册
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/3 14:15
|
||||
*/
|
||||
@Configuration
|
||||
public class CacheBeanConfig {
|
||||
|
||||
/* ================= USER ================= */
|
||||
@Bean("userTokenNativeCache")
|
||||
public Cache userTokens(CacheManager manager) {
|
||||
return require(manager, "user-tokens");
|
||||
}
|
||||
|
||||
// TypedCache 封装层
|
||||
@Bean
|
||||
public UserTokenTypedCache userTokensCache(
|
||||
@Qualifier("userTokenNativeCache") Cache cache) {
|
||||
return new UserTokenTypedCache(cache);
|
||||
}
|
||||
|
||||
/* ================= SAR ================= */
|
||||
@Bean("sarPermanentNativeCache")
|
||||
public Cache sarPermanent(CacheManager manager) {
|
||||
return require(manager, "sar-permanent");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SarTypedCache sarPermanentCache(
|
||||
@Qualifier("sarPermanentNativeCache") Cache cache) {
|
||||
return new SarTypedCache(cache);
|
||||
}
|
||||
|
||||
@Bean("sarShortNativeCache")
|
||||
public Cache sarShort(CacheManager manager) {
|
||||
return require(manager, "sar-short");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SarTypedCache sarShortCache(
|
||||
@Qualifier("sarShortNativeCache") Cache cache) {
|
||||
return new SarTypedCache(cache);
|
||||
}
|
||||
|
||||
/* ================= UAV ================= */
|
||||
@Bean("uavPermanentNativeCache")
|
||||
public Cache uavPermanent(CacheManager manager) {
|
||||
return require(manager, "uav-permanent");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UavTypedCache uavPermanentCache(
|
||||
@Qualifier("uavPermanentNativeCache") Cache cache) {
|
||||
return new UavTypedCache(cache);
|
||||
}
|
||||
|
||||
@Bean("uavShortNativeCache")
|
||||
public Cache uavShort(CacheManager manager) {
|
||||
return require(manager, "uav-short");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UavTypedCache uavShortCache(
|
||||
@Qualifier("uavShortNativeCache") Cache cache) {
|
||||
return new UavTypedCache(cache);
|
||||
}
|
||||
|
||||
/* ================= IMAGE ================= */
|
||||
@Bean("imageJoinNativeCache")
|
||||
public Cache imageJoin(CacheManager manager) {
|
||||
return require(manager, "image-join-short");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserTokenTypedCache imageJoinCache(
|
||||
@Qualifier("imageJoinNativeCache") Cache cache) {
|
||||
return new UserTokenTypedCache(cache);
|
||||
}
|
||||
|
||||
private Cache require(CacheManager manager, String name) {
|
||||
Cache cache = manager.getCache(name);
|
||||
if (cache == null) {
|
||||
throw new IllegalStateException("未找到缓存: " + name);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.zhangy.skyeye.publics.config;
|
||||
package com.zhangy.skyeye.cache.config;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -52,12 +52,12 @@ public class CacheConfig {
|
||||
cacheManager.registerCustomCache("uav-permanent", Caffeine.newBuilder()
|
||||
.maximumSize(5000) // 根据无人机数量调整
|
||||
.build());
|
||||
cacheManager.registerCustomCache("uav-status", Caffeine.newBuilder()
|
||||
cacheManager.registerCustomCache("uav-short", Caffeine.newBuilder()
|
||||
.expireAfterWrite(10, TimeUnit.MINUTES) // 与原 CACHE_EXPIRE_SECONDS 一致
|
||||
.maximumSize(1000) // 按设备/IP 数量预估
|
||||
.recordStats()
|
||||
.build());
|
||||
cacheManager.registerCustomCache("image-join-state", Caffeine.newBuilder()
|
||||
cacheManager.registerCustomCache("image-join-short", Caffeine.newBuilder()
|
||||
.expireAfterWrite(24, TimeUnit.HOURS) // 与原 CACHE_EXPIRE_SECOND 一致
|
||||
.maximumSize(5000) // 航线数量预估
|
||||
.build());
|
||||
@ -0,0 +1,85 @@
|
||||
package com.zhangy.skyeye.cache.debug;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 缓存调试工具(统一查看所有缓存)
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/6 12:55
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/debug/cache")
|
||||
@RequiredArgsConstructor
|
||||
@Profile("dev")
|
||||
public class CacheDebugController {
|
||||
|
||||
private final CacheDebugService cacheDebugService;
|
||||
|
||||
/**
|
||||
* 查看所有缓存
|
||||
*/
|
||||
@GetMapping("/all")
|
||||
public Map<String, Object> allCaches() {
|
||||
return cacheDebugService.allCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看缓存key
|
||||
*/
|
||||
@GetMapping("/keys/{name}")
|
||||
public Set<Object> keys(@PathVariable String name) {
|
||||
return cacheDebugService.keys(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看某个缓存
|
||||
*/
|
||||
@GetMapping("/{name}")
|
||||
public Map<Object, Object> cache(@PathVariable String name) {
|
||||
return cacheDebugService.cache(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看某个key
|
||||
*/
|
||||
@GetMapping("/{name}/{key}")
|
||||
public Object get(@PathVariable String name,
|
||||
@PathVariable String key) {
|
||||
return cacheDebugService.get(name, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除key
|
||||
*/
|
||||
@DeleteMapping("/{name}/{key}")
|
||||
public String evict(@PathVariable String name,
|
||||
@PathVariable String key) {
|
||||
|
||||
cacheDebugService.evict(name, key);
|
||||
return "OK";
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
@DeleteMapping("/{name}")
|
||||
public String clear(@PathVariable String name) {
|
||||
|
||||
cacheDebugService.clear(name);
|
||||
return "OK";
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存统计
|
||||
*/
|
||||
@GetMapping("/stats")
|
||||
public Object stats() {
|
||||
return cacheDebugService.stats();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.zhangy.skyeye.cache.debug;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.stats.CacheStats;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 监控逻辑
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/6 13:02
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Profile("dev")
|
||||
public class CacheDebugService {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
public Map<String, Object> allCaches() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
for (String name : cacheManager.getCacheNames()) {
|
||||
map.put(name, cache(name));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map<Object, Object> cache(String name) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (!(cache instanceof CaffeineCache)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return ((CaffeineCache) cache)
|
||||
.getNativeCache()
|
||||
.asMap();
|
||||
}
|
||||
|
||||
public Set<Object> keys(String name) {
|
||||
return cache(name).keySet();
|
||||
}
|
||||
|
||||
public Object get(String name, Object key) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache == null) {
|
||||
return null;
|
||||
}
|
||||
Cache.ValueWrapper value = cache.get(key);
|
||||
return value == null ? null : value.get();
|
||||
}
|
||||
|
||||
public void evict(String name, Object key) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
cache.evict(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(String name) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> stats() {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
for (String name : cacheManager.getCacheNames()) {
|
||||
Cache cache = cacheManager.getCache(name);
|
||||
if (!(cache instanceof CaffeineCache)) {
|
||||
continue;
|
||||
}
|
||||
CaffeineCache caffeine = (CaffeineCache) cache;
|
||||
CacheStats stats = caffeine.getNativeCache().stats();
|
||||
Map<String, Object> info = new HashMap<>();
|
||||
info.put("size", caffeine.getNativeCache().asMap().size());
|
||||
info.put("hitCount", stats.hitCount());
|
||||
info.put("missCount", stats.missCount());
|
||||
info.put("hitRate", stats.hitRate());
|
||||
info.put("evictionCount", stats.evictionCount());
|
||||
result.put(name, info);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.zhangy.skyeye.cache.debug;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.*;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 自动监控缓存操作
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/6 13:06
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@Profile("dev")
|
||||
public class CacheMonitorAspect {
|
||||
|
||||
@After("execution(* org.springframework.cache.Cache.put(..))")
|
||||
public void afterPut(JoinPoint jp) {
|
||||
Cache cache = (Cache) jp.getTarget();
|
||||
Object key = jp.getArgs()[0];
|
||||
log.debug("CACHE PUT -> {} : {}",
|
||||
cache.getName(),
|
||||
key);
|
||||
}
|
||||
|
||||
@After("execution(* org.springframework.cache.Cache.get(..))")
|
||||
public void afterGet(JoinPoint jp) {
|
||||
Cache cache = (Cache) jp.getTarget();
|
||||
Object key = jp.getArgs()[0];
|
||||
log.debug("CACHE GET -> {} : {}",
|
||||
cache.getName(),
|
||||
key);
|
||||
}
|
||||
|
||||
@After("execution(* org.springframework.cache.Cache.evict(..))")
|
||||
public void afterEvict(JoinPoint jp) {
|
||||
Cache cache = (Cache) jp.getTarget();
|
||||
Object key = jp.getArgs()[0];
|
||||
log.warn("CACHE EVICT -> {} : {}",
|
||||
cache.getName(),
|
||||
key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package com.zhangy.skyeye.cache.debug;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 实时监控任务
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/6 13:07
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Profile("dev")
|
||||
public class CacheWatcherUltimate {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
@Scheduled(fixedDelay = 30000)
|
||||
public void watchCaches() {
|
||||
log.info("========== CACHE STATUS BEGIN ==========");
|
||||
for (String name : cacheManager.getCacheNames()) {
|
||||
org.springframework.cache.Cache springCache = cacheManager.getCache(name);
|
||||
if (!(springCache instanceof CaffeineCache)) {
|
||||
continue;
|
||||
}
|
||||
CaffeineCache caffeineCache = (CaffeineCache) springCache;
|
||||
Cache<Object, Object> nativeCache = caffeineCache.getNativeCache();
|
||||
Map<Object, Object> map = nativeCache.asMap();
|
||||
log.info("CACHE [{}] SIZE = {}", name, map.size());
|
||||
for (Map.Entry<Object, Object> entry : map.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
log.info(
|
||||
" KEY = {} | VALUE_TYPE = {}",
|
||||
key,
|
||||
value == null ? "null" : value.getClass().getSimpleName()
|
||||
);
|
||||
}
|
||||
}
|
||||
log.info("========== CACHE STATUS END ==========");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package com.zhangy.skyeye.cache.image;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: IMAGE 缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/5 15:56
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ImageCache {
|
||||
|
||||
private final Map<String, ImageJoinTypedCache> caches;
|
||||
|
||||
private ImageJoinTypedCache getShort() {
|
||||
return caches.get("imageJoinShortCache");
|
||||
}
|
||||
|
||||
public void put(String key, Object value) {
|
||||
getShort().putValue(key, value);
|
||||
}
|
||||
|
||||
public <T> T get(String key, Class<T> clazz) {
|
||||
return getShort().getValue(key, clazz);
|
||||
}
|
||||
|
||||
public void evict(String key) {
|
||||
getShort().evictValue(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package com.zhangy.skyeye.cache.image;
|
||||
|
||||
import com.zhangy.skyeye.cache.AbstractTypedCache;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: IMAGE 缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/5 15:55
|
||||
*/
|
||||
public class ImageJoinTypedCache extends AbstractTypedCache {
|
||||
|
||||
public ImageJoinTypedCache(Cache cache) {
|
||||
super(cache);
|
||||
}
|
||||
|
||||
public void putValue(String key, Object value) {
|
||||
super.put(key, value);
|
||||
}
|
||||
|
||||
public <T> T getValue(String key, Class<T> clazz) {
|
||||
return super.get(key, clazz);
|
||||
}
|
||||
|
||||
public void evictValue(String key) {
|
||||
super.evict(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package com.zhangy.skyeye.cache.publics;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 业务聚合层:对外暴露用户 token 操作
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/5 14:06
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UserTokenCache {
|
||||
|
||||
private final Map<String, UserTokenTypedCache> caches;
|
||||
|
||||
private UserTokenTypedCache getUserTokenCache() {
|
||||
return caches.get("userTokensCache");
|
||||
}
|
||||
|
||||
// 保存 token
|
||||
public void storeToken(String tokenKey, String token) {
|
||||
getUserTokenCache().put(tokenKey, token);
|
||||
}
|
||||
|
||||
// 获取并验证 token 是否一致
|
||||
public boolean validateToken(String tokenKey, String currentToken) {
|
||||
String stored = getUserTokenCache().get(tokenKey);
|
||||
return stored != null && stored.equals(currentToken);
|
||||
}
|
||||
|
||||
// 获取 token
|
||||
public String getToken(String tokenKey) {
|
||||
return getUserTokenCache().get(tokenKey);
|
||||
}
|
||||
|
||||
// 删除 token
|
||||
public void evictToken(String tokenKey) {
|
||||
getUserTokenCache().evictValue(tokenKey);
|
||||
}
|
||||
|
||||
public Object getNativeCache() {
|
||||
return getUserTokenCache().getNativeCacheObject(); // UserTokenTypedCache 里需要有 getCache()
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package com.zhangy.skyeye.cache.publics;
|
||||
|
||||
import com.zhangy.skyeye.cache.AbstractTypedCache;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 安全封装 User Token Cache
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/5 14:14
|
||||
*/
|
||||
public class UserTokenTypedCache extends AbstractTypedCache {
|
||||
|
||||
public UserTokenTypedCache(Cache cache) {
|
||||
super(cache);
|
||||
}
|
||||
|
||||
public void put(String key, String token) {
|
||||
super.put(key, token);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return super.get(key, String.class);
|
||||
}
|
||||
|
||||
public void evictValue(String key) {
|
||||
super.evict(key);
|
||||
}
|
||||
|
||||
public Object getNativeCacheObject() {
|
||||
return super.getNativeCache(); // UserTokenTypedCache 里需要有 getCache()
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package com.zhangy.skyeye.cache.sar;
|
||||
|
||||
import com.zhangy.skyeye.device.entity.SkyeyePayload;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.sar.dto.SarErrorDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: Sar 缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/3 14:24
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SarCache {
|
||||
|
||||
private final Map<String, SarTypedCache> caches;
|
||||
|
||||
private SarTypedCache getPermanent() {
|
||||
return caches.get("sarPermanentCache");
|
||||
}
|
||||
|
||||
private SarTypedCache getShort() {
|
||||
return caches.get("sarShortCache");
|
||||
}
|
||||
|
||||
/* ========== 永久缓存:SAR 载荷操作 ========== */
|
||||
// 缓存 SAR 载荷
|
||||
public void cacheSar(SkyeyePayload sar) {
|
||||
getPermanent().putValue(sar.getId().toString(), sar);
|
||||
}
|
||||
|
||||
// 获取单个 SAR
|
||||
public SkyeyePayload getOne(Long sarId) {
|
||||
return getPermanent().getValue(sarId.toString(), SkyeyePayload.class);
|
||||
}
|
||||
|
||||
// 删除指定 SAR
|
||||
public void evictSar(Long sarId) {
|
||||
getPermanent().evictValue(sarId.toString());
|
||||
}
|
||||
|
||||
// 获取永久缓存中所有 SAR 对象
|
||||
public List<SkyeyePayload> getAll() {
|
||||
Map<Object, Object> map = getPermanent().asMap();
|
||||
if (map == null || map.isEmpty()) return List.of();
|
||||
return map.values().stream()
|
||||
.filter(v -> v instanceof SkyeyePayload)
|
||||
.map(v -> (SkyeyePayload) v)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/* ========== 连接状态 ========== */
|
||||
public void markConnected(String ip) {
|
||||
getPermanent().putValue(CacheKey.getSarConnected(ip), Boolean.TRUE);
|
||||
}
|
||||
|
||||
public boolean isConnected(String ip) {
|
||||
return getPermanent().getValue(CacheKey.getSarConnected(ip), Boolean.class) != null;
|
||||
}
|
||||
|
||||
public void removeConnection(String ip) {
|
||||
getPermanent().evictValue(CacheKey.getSarConnected(ip));
|
||||
}
|
||||
|
||||
/* ========== 实时状态 ========== */
|
||||
public void saveStatus(String ip, JmSarStatusDTO dto) {
|
||||
getShort().putValue(CacheKey.getSarStatus(ip), dto);
|
||||
}
|
||||
|
||||
public JmSarStatusDTO getLatestStatus(String ip) {
|
||||
return getShort().getValue(CacheKey.getSarStatus(ip), JmSarStatusDTO.class);
|
||||
}
|
||||
|
||||
/* ========== 控制回执 ========== */
|
||||
public void saveControlBack(String ip, SarErrorDTO dto) {
|
||||
getShort().putValue(CacheKey.getSarControlBack(ip), dto);
|
||||
}
|
||||
|
||||
public SarErrorDTO getControlBack(String ip) {
|
||||
return getShort().getValue(CacheKey.getSarControlBack(ip), SarErrorDTO.class);
|
||||
}
|
||||
|
||||
public void clearControlBack(String ip) {
|
||||
getShort().evictValue(CacheKey.getSarControlBack(ip));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package com.zhangy.skyeye.cache.sar;
|
||||
|
||||
import com.zhangy.skyeye.cache.AbstractTypedCache;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: 通用 SAR 缓存,可作为永久或短期缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/5 12:06
|
||||
*/
|
||||
public class SarTypedCache extends AbstractTypedCache {
|
||||
|
||||
public SarTypedCache(Cache cache) {
|
||||
super(cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全读取
|
||||
*/
|
||||
public <T> T getValue(String key, Class<T> type) {
|
||||
return super.get(key, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全写入
|
||||
*/
|
||||
public void putValue(String key, Object value) {
|
||||
super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全删除
|
||||
*/
|
||||
public void evictValue(String key) {
|
||||
super.evict(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
package com.zhangy.skyeye.cache.uav;
|
||||
|
||||
import com.zhangy.skyeye.cache.sar.SarTypedCache;
|
||||
import com.zhangy.skyeye.device.entity.SkyeyeUav;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: Uav 缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/4 14:19
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UavCache {
|
||||
|
||||
private final Map<String, UavTypedCache> caches;
|
||||
|
||||
private UavTypedCache getPermanent() {
|
||||
return caches.get("uavPermanentCache");
|
||||
}
|
||||
|
||||
private UavTypedCache getShort() {
|
||||
return caches.get("uavShortCache");
|
||||
}
|
||||
|
||||
/* ========== 永久缓存:UAV 操作 ========== */
|
||||
public void put(SkyeyeUav uav) {
|
||||
getPermanent().putValue(uav.getId().toString(), uav);
|
||||
}
|
||||
|
||||
public SkyeyeUav get(Long id) {
|
||||
return getPermanent().getValue(id.toString(), SkyeyeUav.class);
|
||||
}
|
||||
|
||||
public void evict(Long id) {
|
||||
getPermanent().evictValue(id.toString());
|
||||
}
|
||||
|
||||
public List<SkyeyeUav> getAll() {
|
||||
Map<Object, Object> map = getPermanent().asMap();
|
||||
if (map == null) {
|
||||
return List.of();
|
||||
}
|
||||
return map.values().stream()
|
||||
.map(v -> (SkyeyeUav) v)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/* ========== 短期缓存 ========== */
|
||||
public void putShort(String key, Object value) {
|
||||
getShort().putValue(key, value);
|
||||
}
|
||||
|
||||
public <T> T getShort(String key, Class<T> clazz) {
|
||||
return getShort().getValue(key, clazz);
|
||||
}
|
||||
|
||||
public void evictShort(String key) {
|
||||
getShort().evictValue(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.zhangy.skyeye.cache.uav;
|
||||
|
||||
import com.zhangy.skyeye.cache.AbstractTypedCache;
|
||||
import org.springframework.cache.Cache;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem_online
|
||||
* @DESCRIPTION: Uav 缓存,可作为永久或短期缓存
|
||||
* @AUTHOR: GuanCheng Long
|
||||
* @DATE: 2026/3/4 14:20
|
||||
*/
|
||||
public class UavTypedCache extends AbstractTypedCache {
|
||||
|
||||
public UavTypedCache(Cache cache) {
|
||||
super(cache);
|
||||
}
|
||||
|
||||
public <T> T getValue(String key, Class<T> type) {
|
||||
return super.get(key, type);
|
||||
}
|
||||
|
||||
public void putValue(String key, Object value) {
|
||||
super.put(key, value);
|
||||
}
|
||||
|
||||
public void evictValue(String key) {
|
||||
super.evict(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.zhangy.skyeye.device.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
import com.zhangy.skyeye.common.extend.dto.QueryDTO;
|
||||
import com.zhangy.skyeye.common.extend.enums.EnumUtil;
|
||||
@ -15,14 +16,11 @@ import com.zhangy.skyeye.jm.dto.JmJobStatusDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.consts.ExecStatusEnum;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import com.zhangy.skyeye.sar.service.ISarControlService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -33,47 +31,26 @@ import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PayloadServiceImpl implements IPayloadService {
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
@Autowired
|
||||
private PayloadMapper payloadMapper;
|
||||
|
||||
@Autowired
|
||||
private JmJobStatusService sarJobStatusService;
|
||||
|
||||
@Autowired
|
||||
private ISarControlService sarControlService;
|
||||
|
||||
private Cache sarPermanentCache; // SAR 专用永久缓存
|
||||
private Cache sarShortCache; // 短时状态
|
||||
private final SarCache sarCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initAndCacheAllSar() {
|
||||
// 初始化缓存实例(获取“盒子”)
|
||||
sarPermanentCache = cacheManager.getCache("device-permanent");
|
||||
sarShortCache = cacheManager.getCache("sar-short-lived");
|
||||
// 防护检查(不抛异常,而是日志 + 降级)
|
||||
if (sarPermanentCache == null) {
|
||||
log.error("device-permanent 缓存未找到!请检查 CacheConfig 是否正确注册");
|
||||
throw new IllegalStateException("device-permanent 缓存未找到");
|
||||
}
|
||||
if (sarShortCache == null) {
|
||||
log.error("sar-short-lived 缓存未找到!请检查 CacheConfig");
|
||||
throw new IllegalStateException("sar-short-lived 缓存未找到");
|
||||
}
|
||||
// 开始缓存所有 SAR(如果 permanentCache 为 null,这里会安全跳过)
|
||||
PayloadQueryDTO payloadQueryDTO = new PayloadQueryDTO();
|
||||
payloadQueryDTO.setType(PayloadTypeEnum.SAR.getCode());
|
||||
List<SkyeyePayload> sarList = selectList(payloadQueryDTO);
|
||||
if (sarPermanentCache != null) {
|
||||
sarList.forEach(this::cacheSar);
|
||||
sarList.forEach(sarCache::cacheSar);
|
||||
log.info("SAR 载荷缓存完成,共 {} 条", sarList.size());
|
||||
} else {
|
||||
log.warn("永久缓存不可用,跳过 SAR 预加载");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,34 +58,25 @@ public class PayloadServiceImpl implements IPayloadService {
|
||||
return payloadMapper.selectPage(param);
|
||||
}
|
||||
|
||||
private void cacheSar(SkyeyePayload e) {
|
||||
if (sarPermanentCache != null) {
|
||||
sarPermanentCache.put(e.getId().toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SkyeyePayload> getSar(Long... sarId) {
|
||||
if (ObjectUtil.isNotEmpty(sarId)) {
|
||||
return Arrays.stream(sarId)
|
||||
.map(id -> CacheUtil.get(sarPermanentCache, id.toString(), SkyeyePayload.class))
|
||||
.map(sarCache::getOne)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 获取所有 SAR(全量从缓存读取)
|
||||
com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache =
|
||||
(com.github.benmanes.caffeine.cache.Cache<Object, Object>) sarPermanentCache.getNativeCache();
|
||||
|
||||
return nativeCache.asMap().values().stream()
|
||||
.filter(v -> v instanceof SkyeyePayload)
|
||||
.map(v -> (SkyeyePayload) v)
|
||||
return sarCache.getAll().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkyeyePayload getOne(Long payloadId) {
|
||||
return CacheUtil.get(sarPermanentCache, payloadId.toString(), SkyeyePayload.class);
|
||||
return sarCache.getOne(payloadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -131,11 +99,10 @@ public class PayloadServiceImpl implements IPayloadService {
|
||||
.map(JmUavStatusDTO::getSarId) // 正确取 SAR ID
|
||||
.collect(Collectors.toSet());
|
||||
// 筛选出未在任务中且已连接的雷达
|
||||
List<SkyeyePayload> payloadList = sarList.stream()
|
||||
return sarList.stream()
|
||||
.filter(sar -> !jobSarSet.contains(sar.getId())
|
||||
&& CacheUtil.get(sarShortCache, CacheKey.getSarStatus(sar.getIp()), JmSarStatusDTO.class) != null)
|
||||
&& sarCache.getLatestStatus(sar.getIp()) != null)
|
||||
.collect(Collectors.toList());
|
||||
return payloadList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -159,7 +126,7 @@ public class PayloadServiceImpl implements IPayloadService {
|
||||
} else {
|
||||
payloadMapper.insert(e);
|
||||
}
|
||||
cacheSar(e);
|
||||
sarCache.cacheSar(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -173,9 +140,7 @@ public class PayloadServiceImpl implements IPayloadService {
|
||||
payloadMapper.update(e);
|
||||
// 若是sar则更新缓存
|
||||
List<SkyeyePayload> list = selectById(PayloadTypeEnum.SAR, e.getId());
|
||||
if (ObjectUtil.isNotEmpty(list)) {
|
||||
cacheSar(list.get(0));
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(list)) sarCache.cacheSar(list.get(0));
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -219,18 +184,17 @@ public class PayloadServiceImpl implements IPayloadService {
|
||||
}
|
||||
|
||||
payloadMapper.deleteLogic(id);
|
||||
Arrays.stream(id).forEach(i -> sarPermanentCache.evict(i.toString()));
|
||||
Arrays.stream(id).forEach(sarCache::evictSar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JmSarStatusDTO getLastStatus(String payloadIp) {
|
||||
String statusKey = CacheKey.getSarStatus(payloadIp);
|
||||
JmSarStatusDTO status = CacheUtil.get(sarShortCache, statusKey, JmSarStatusDTO.class);
|
||||
JmSarStatusDTO status = sarCache.getLatestStatus(payloadIp);
|
||||
if (status == null) {
|
||||
try {
|
||||
sarControlService.connect(payloadIp);
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
status = CacheUtil.get(sarShortCache, statusKey, JmSarStatusDTO.class);
|
||||
status = sarCache.getLatestStatus(payloadIp);
|
||||
} catch (InterruptedException ex) {
|
||||
throw new ServiceException("获取雷达状态失败:" + ex.getMessage());
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.zhangy.skyeye.device.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.zhangy.skyeye.cache.uav.UavCache;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
import com.zhangy.skyeye.common.extend.exception.ServiceException;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
@ -10,10 +11,8 @@ import com.zhangy.skyeye.device.service.IUavService;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.publics.consts.ExecStatusEnum;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -25,6 +24,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UavServiceImpl implements IUavService {
|
||||
|
||||
@Autowired
|
||||
@ -33,26 +33,11 @@ public class UavServiceImpl implements IUavService {
|
||||
@Autowired
|
||||
private JmJobStatusService sarJobStatusService;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private Cache permanentCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initCache() {
|
||||
permanentCache = cacheManager.getCache("sar-permanent");
|
||||
if (permanentCache == null) {
|
||||
throw new IllegalStateException("永久缓存 sar-permanent 未找到,请检查 CacheConfig 配置");
|
||||
}
|
||||
}
|
||||
private final UavCache uavCache;
|
||||
|
||||
@PostConstruct
|
||||
public void cacheAll() {
|
||||
selectList(null).forEach(this::cache);
|
||||
}
|
||||
|
||||
private void cache(SkyeyeUav e) {
|
||||
permanentCache.put(e.getId().toString(), e);
|
||||
selectList(null).forEach(uavCache::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,17 +59,17 @@ public class UavServiceImpl implements IUavService {
|
||||
public List<SkyeyeUav> get(Long... id) {
|
||||
if (ObjectUtil.isNotEmpty(id)) {
|
||||
return Arrays.stream(id)
|
||||
.map(i -> CacheUtil.get(permanentCache, i.toString(), SkyeyeUav.class))
|
||||
.map(uavCache::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// 全量获取
|
||||
return CacheUtil.getAll(permanentCache, SkyeyeUav.class);
|
||||
return uavCache.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SkyeyeUav getOne(Long id) {
|
||||
SkyeyeUav uav = (SkyeyeUav) permanentCache.get(id.toString());
|
||||
SkyeyeUav uav = uavCache.get(id);
|
||||
if (uav != null) {
|
||||
return uav;
|
||||
}
|
||||
@ -95,7 +80,7 @@ public class UavServiceImpl implements IUavService {
|
||||
throw new ServiceException("无效的无人机ID:" + id);
|
||||
}
|
||||
uav = list.get(0);
|
||||
cache(uav);
|
||||
uavCache.put(uav);
|
||||
return uav;
|
||||
}
|
||||
|
||||
@ -128,7 +113,7 @@ public class UavServiceImpl implements IUavService {
|
||||
} else {
|
||||
uavMapper.insert(e);
|
||||
}
|
||||
cache(e);
|
||||
uavCache.put(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -140,7 +125,7 @@ public class UavServiceImpl implements IUavService {
|
||||
// 若是sar则更新缓存
|
||||
List<SkyeyeUav> list = selectById(e.getId());
|
||||
if (ObjectUtil.isNotEmpty(list)) {
|
||||
cache(list.get(0));
|
||||
uavCache.put(list.get(0));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
@ -179,6 +164,6 @@ public class UavServiceImpl implements IUavService {
|
||||
}
|
||||
}
|
||||
uavMapper.deleteLogic(ids);
|
||||
Arrays.stream(ids).forEach(id -> permanentCache.evict(id.toString()));
|
||||
Arrays.stream(ids).forEach(uavCache::evict);
|
||||
}
|
||||
}
|
||||
@ -3,9 +3,8 @@ package com.zhangy.skyeye.jm.task;
|
||||
import com.zhangy.skyeye.device.entity.SkyeyePayload;
|
||||
import com.zhangy.skyeye.device.service.IPayloadService;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.service.ISysLoginService;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
import com.zhangy.skyeye.sar.exception.SarConnectException;
|
||||
import com.zhangy.skyeye.sar.service.ISarControlService;
|
||||
@ -13,13 +12,11 @@ import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 任务管理定时任务
|
||||
@ -42,16 +39,7 @@ public class JmTaskScheduler {
|
||||
private IPayloadService payloadService;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private Cache sarPermanentCache;
|
||||
private Cache sarShortCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initCaches() {
|
||||
sarPermanentCache = cacheManager.getCache("sar-permanent");
|
||||
sarShortCache = cacheManager.getCache("sar-short");
|
||||
}
|
||||
private SarCache sarCache; // ← 直接用领域缓存
|
||||
|
||||
/**
|
||||
* 每1秒向前端推送雷达状态信息,断开连接则所有数据置0返回
|
||||
@ -118,11 +106,11 @@ public class JmTaskScheduler {
|
||||
sarList.forEach(sar -> {
|
||||
String ip = sar.getIp();
|
||||
// 判断是否已连接:看 shortCache 里是否有该 ip 的状态(最近有状态包)
|
||||
boolean hasStatus = CacheUtil.get(sarShortCache, CacheKey.getSarStatus(ip), JmSarStatusDTO.class) != null;
|
||||
JmSarStatusDTO status = sarCache.getLatestStatus(ip);
|
||||
// 判断是否已执行连接指令:看 permanentCache 里是否有该 ip 的连接标志
|
||||
boolean hasConnectedFlag = sarPermanentCache.get(ip) != null;
|
||||
boolean hasConnectedFlag = sarCache.isConnected(ip);
|
||||
// 如果缺少状态 或 缺少连接标志,则尝试连接
|
||||
if (!hasConnectedFlag || !hasStatus) {
|
||||
if (!hasConnectedFlag || Objects.isNull(status)) {
|
||||
try {
|
||||
controlInfoService.sendUdp(ip, SarControlTypeEnum.CONNECT);
|
||||
log.info("尝试连接 SAR IP: {}", ip);
|
||||
|
||||
@ -2,6 +2,7 @@ package com.zhangy.skyeye.publics.advice;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.zhangy.skyeye.cache.publics.UserTokenCache;
|
||||
import com.zhangy.skyeye.common.extend.anno.IgnoreAuth;
|
||||
import com.zhangy.skyeye.common.extend.exception.AuthException;
|
||||
import com.zhangy.skyeye.common.extend.util.JsonUtil;
|
||||
@ -10,8 +11,6 @@ import com.zhangy.skyeye.publics.dto.UserDTO;
|
||||
import com.zhangy.skyeye.publics.utils.SecurityUtil;
|
||||
import com.zhangy.skyeye.publics.utils.SpringContextUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
@ -38,14 +37,8 @@ import java.util.Objects;
|
||||
@Component
|
||||
public class AuthInterceptor implements AsyncHandlerInterceptor {
|
||||
|
||||
private CacheManager getCacheManager() {
|
||||
return SpringContextUtil.getBean(CacheManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
CacheManager cacheManager = getCacheManager();
|
||||
Objects.requireNonNull(cacheManager, "CacheManager 未被 Spring 注入,请检查配置");
|
||||
// 放行 CORS 预检请求(OPTIONS),由后续 Filter 统一处理跨域头
|
||||
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod())) {
|
||||
return true;
|
||||
@ -65,6 +58,10 @@ public class AuthInterceptor implements AsyncHandlerInterceptor {
|
||||
if (method.isAnnotationPresent(IgnoreAuth.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 注入 UserTokenCache
|
||||
UserTokenCache userTokenCache = SpringContextUtil.getBean(UserTokenCache.class);
|
||||
|
||||
// 获取并校验 token
|
||||
String token = SecurityUtil.getToken(request);
|
||||
if (StrUtil.isBlank(token)) {
|
||||
@ -94,13 +91,8 @@ public class AuthInterceptor implements AsyncHandlerInterceptor {
|
||||
if (StrUtil.isBlank(tokenKey)) {
|
||||
throw new AuthException("用户信息异常,请重新登录");
|
||||
}
|
||||
Cache cache = cacheManager.getCache("user-tokens");
|
||||
// 从 Caffeine 获取
|
||||
if (cache == null) {
|
||||
throw new AuthException("登录状态已失效,请重新登录");
|
||||
}
|
||||
// CaffeineCache 中的 token 与当前请求不一致 → 多设备登录,被踢
|
||||
String storedToken = cache.get(tokenKey, String.class);
|
||||
String storedToken = userTokenCache.getToken(tokenKey);
|
||||
if (storedToken == null) {
|
||||
// 显式处理 null,即 token 已失效或被移除
|
||||
throw new AuthException("登录状态已失效,请重新登录");
|
||||
@ -111,7 +103,7 @@ public class AuthInterceptor implements AsyncHandlerInterceptor {
|
||||
throw new AuthException("该账号已在其他设备登录,请重新登录");
|
||||
}
|
||||
// 续期:Caffeine 的 expireAfterWrite 是从最后写入开始算,所以 put 一下即可续期
|
||||
Objects.requireNonNull(cacheManager.getCache("user-tokens")).put(tokenKey, storedToken);
|
||||
userTokenCache.storeToken(tokenKey, storedToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.zhangy.skyeye.publics.controller;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.zhangy.skyeye.cache.publics.UserTokenCache;
|
||||
import com.zhangy.skyeye.common.extend.anno.IgnoreAuth;
|
||||
import com.zhangy.skyeye.common.extend.anno.OperationLog;
|
||||
import com.zhangy.skyeye.common.extend.dto.PageDTO;
|
||||
@ -10,7 +11,6 @@ import com.zhangy.skyeye.common.extend.util.MessageUtils;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.common.pojo.result.Result;
|
||||
import com.zhangy.skyeye.common.utils.JwtUtil;
|
||||
import com.zhangy.skyeye.redis.utils.RedisUtil;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.dto.RegisterDTO;
|
||||
import com.zhangy.skyeye.publics.dto.SysUserPwdDTO;
|
||||
@ -19,7 +19,7 @@ import com.zhangy.skyeye.publics.entity.SysLog;
|
||||
import com.zhangy.skyeye.publics.entity.SysUser;
|
||||
import com.zhangy.skyeye.publics.service.ISysUserService;
|
||||
import com.zhangy.skyeye.publics.utils.SecurityUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -30,7 +30,7 @@ import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@RequestMapping("/user")
|
||||
public class SysUserController {
|
||||
@ -38,14 +38,11 @@ public class SysUserController {
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
/** token失效时间(秒) */
|
||||
private final int TOKEN_EXPIRE = 60 * 60 * 24;
|
||||
private final UserTokenCache userTokenCache;
|
||||
|
||||
/**
|
||||
* 登录接口
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@IgnoreAuth
|
||||
@ -57,15 +54,17 @@ public class SysUserController {
|
||||
throw ServiceException.noLog(MessageUtils.message("user.login.error"));
|
||||
}
|
||||
UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
|
||||
String key = JSONUtil.toJsonStr(userDTO);
|
||||
String accessToken = JwtUtil.sign(key, user.getPassword());
|
||||
redisUtil.set(userDTO.getTokenKey(), accessToken, TOKEN_EXPIRE);
|
||||
String payload = JSONUtil.toJsonStr(userDTO); // 保持原逻辑
|
||||
String accessToken = JwtUtil.sign(payload, user.getPassword());
|
||||
String tokenKey = userDTO.getTokenKey(); // skyeye:user:token:id@account
|
||||
userTokenCache.storeToken(tokenKey, accessToken);
|
||||
userDTO.setToken(accessToken);
|
||||
return Result.successData(MessageUtils.message("user.login.success"), userDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@ -94,8 +93,8 @@ public class SysUserController {
|
||||
public Result logout() {
|
||||
UserDTO userDTO = SecurityUtil.getUser();
|
||||
if (userDTO != null) {
|
||||
String key = CacheKey.getToekn(userDTO.getId(), userDTO.getAccount());
|
||||
redisUtil.del(key);
|
||||
String tokenKey = CacheKey.getToken(userDTO.getId(), userDTO.getAccount());
|
||||
userTokenCache.evictToken(tokenKey);
|
||||
}
|
||||
return Result.status(true);
|
||||
}
|
||||
|
||||
@ -1,44 +1,25 @@
|
||||
package com.zhangy.skyeye.publics.service.impl;
|
||||
|
||||
import com.zhangy.skyeye.cache.publics.UserTokenCache;
|
||||
import com.zhangy.skyeye.publics.service.ISysLoginService;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysLoginServiceImpl implements ISysLoginService {
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private Cache userTokensCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initCache() {
|
||||
userTokensCache = cacheManager.getCache("user-tokens");
|
||||
if (userTokensCache == null) {
|
||||
throw new IllegalStateException("user-tokens 缓存未找到,请检查 CacheConfig 配置");
|
||||
}
|
||||
}
|
||||
private final UserTokenCache userTokenCache;
|
||||
|
||||
@Override
|
||||
public boolean hasLogged() {
|
||||
if (userTokensCache == null) {
|
||||
return false;
|
||||
}
|
||||
// 获取底层 Caffeine Cache
|
||||
return CacheUtil.size(userTokensCache) > 0;
|
||||
return CacheUtil.size(userTokenCache) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countLogged() {
|
||||
if (userTokensCache == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) CacheUtil.size(userTokensCache);
|
||||
return (int) CacheUtil.size(userTokenCache);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.zhangy.skyeye.publics.utils;
|
||||
|
||||
import com.zhangy.skyeye.cache.publics.UserTokenCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -58,5 +59,16 @@ public class CacheUtil {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static long size(UserTokenCache tokenCache) {
|
||||
if (tokenCache == null) return 0;
|
||||
Object nativeCache = tokenCache.getNativeCache();
|
||||
if (nativeCache instanceof com.github.benmanes.caffeine.cache.Cache) {
|
||||
com.github.benmanes.caffeine.cache.Cache<?, ?> caffeineCache =
|
||||
(com.github.benmanes.caffeine.cache.Cache<?, ?>) nativeCache;
|
||||
return caffeineCache.estimatedSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
package com.zhangy.skyeye.sar.context;
|
||||
|
||||
import com.zhangy.skyeye.cache.uav.UavCache;
|
||||
import com.zhangy.skyeye.jm.dto.JmAirlineStatusDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmUavStatusDTO;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* @PROJECT_NAME: skyeyesystem
|
||||
* @DESCRIPTION: SAR 任务上下文提供者实现(基于 Redis 缓存,避免循环依赖)
|
||||
@ -22,20 +18,10 @@ import javax.annotation.PostConstruct;
|
||||
@Component
|
||||
public class SarTaskContextProviderImpl implements SarTaskContextProvider {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
private final UavCache uavCache;
|
||||
|
||||
private Cache uavStatusCache;
|
||||
|
||||
public SarTaskContextProviderImpl(CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initCache() {
|
||||
this.uavStatusCache = cacheManager.getCache("uav-status");
|
||||
if (this.uavStatusCache == null) {
|
||||
log.error("缓存 uav-status 未找到,请检查 CacheConfig 配置");
|
||||
}
|
||||
public SarTaskContextProviderImpl(UavCache uavCache) {
|
||||
this.uavCache = uavCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,9 +30,8 @@ public class SarTaskContextProviderImpl implements SarTaskContextProvider {
|
||||
log.warn("获取 uav 状态失败:payloadIp 为空");
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = "sar:context:uav:" + payloadIp; // 保持原 key 格式
|
||||
return CacheUtil.get(uavStatusCache, key, JmUavStatusDTO.class);
|
||||
return uavCache.getShort(key, JmUavStatusDTO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +67,7 @@ public class SarTaskContextProviderImpl implements SarTaskContextProvider {
|
||||
|
||||
String key = "sar:context:uav:" + payloadIp;
|
||||
try {
|
||||
uavStatusCache.put(key, uavStatus); // 自动过期 10 分钟
|
||||
uavCache.putShort(key, uavStatus);// 自动过期 10 分钟
|
||||
log.debug("已更新缓存:key={}, jobExecId={}", key, uavStatus.getJobExecId());
|
||||
} catch (Exception e) {
|
||||
log.error("更新 SAR uav 状态缓存失败,ip={}", payloadIp, e);
|
||||
@ -97,7 +82,7 @@ public class SarTaskContextProviderImpl implements SarTaskContextProvider {
|
||||
return;
|
||||
}
|
||||
String key = "sar:context:uav:" + payloadIp;
|
||||
uavStatusCache.evict(key);
|
||||
uavCache.evictShort(key);
|
||||
log.debug("SAR uav 缓存已清理:{}", key);
|
||||
}
|
||||
}
|
||||
@ -1,19 +1,15 @@
|
||||
package com.zhangy.skyeye.sar.control;
|
||||
|
||||
import com.zhangy.skyeye.sar.cache.SarCache;
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlParamDTO;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -26,23 +22,11 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class SarControlConnectStrategy implements ISarControlStrategy {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
// 不加 final,因为在 PostConstruct 中初始化
|
||||
private Cache permanentCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initCache() {
|
||||
this.permanentCache = cacheManager.getCache("sar-permanent");
|
||||
if (this.permanentCache == null) {
|
||||
log.error("永久缓存 sar-payload-permanent 未找到,请检查 CacheConfig 配置");
|
||||
}
|
||||
}
|
||||
private final SarCache sarCache;
|
||||
|
||||
@Override
|
||||
public boolean supports(SarControlParamDTO param) {
|
||||
SarControlTypeEnum controlType = param.getControlType();
|
||||
return controlType == SarControlTypeEnum.CONNECT;
|
||||
return param.getControlType() == SarControlTypeEnum.CONNECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,12 +38,9 @@ public class SarControlConnectStrategy implements ISarControlStrategy {
|
||||
|
||||
@Override
|
||||
public void sendPost(SarControlDTO sar) {
|
||||
// 建立连接后,记录连接标志(value 可以是 Date、字符串 "connected" 或 boolean true,随你业务)
|
||||
if (permanentCache != null) {
|
||||
permanentCache.put(sar.getIp(), new Date());
|
||||
} else {
|
||||
log.warn("无法记录连接标志,永久缓存未初始化");
|
||||
}
|
||||
// 建立连接后,记录连接标志
|
||||
sarCache.markConnected(sar.getIp());
|
||||
log.info("SAR [{}] 已标记为连接状态", sar.getIp());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package com.zhangy.skyeye.sar.control;
|
||||
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.common.extend.exception.ServiceException;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlPackDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlParamDTO;
|
||||
@ -14,8 +14,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
@ -23,7 +21,6 @@ import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -61,7 +58,7 @@ public class SarControlContext {
|
||||
private final int POLLING_INTERVAL = 100;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
private SarCache sarCache;
|
||||
|
||||
/**
|
||||
* 应答超时
|
||||
@ -170,17 +167,11 @@ public class SarControlContext {
|
||||
* 轮询等待缓存中的回执(带超时)
|
||||
*/
|
||||
private SarErrorDTO waitForResponse(String cacheKey, String ip, SarControlTypeEnum controlType) {
|
||||
Cache sarShortCache = cacheManager.getCache("sar-short");
|
||||
if (sarShortCache == null) {
|
||||
log.error("无法获取 sar-short cache");
|
||||
return null;
|
||||
}
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - start < ANSWER_TIMEOUT) {
|
||||
SarErrorDTO dto = CacheUtil.get(sarShortCache, cacheKey, SarErrorDTO.class);
|
||||
SarErrorDTO dto = sarCache.getControlBack(ip); // 如果 SarCache 封装了泛型方法可以直接用
|
||||
if (dto != null) {
|
||||
// 读后即删,防止重复消费
|
||||
sarShortCache.evict(cacheKey);
|
||||
sarCache.saveStatus(cacheKey, null); // 清空 shortCache 对应的 key
|
||||
log.info("收到雷达回执 | ip:{} | 控制类型:{} | 状态:{}", ip, controlType, dto.getExecStatus());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
package com.zhangy.skyeye.sar.control;
|
||||
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlParamDTO;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -24,16 +21,7 @@ import java.util.List;
|
||||
@RequiredArgsConstructor
|
||||
public class SarControlDisconnectStrategy implements ISarControlStrategy {
|
||||
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
private Cache sarShortCache;
|
||||
private Cache sarPermanentCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.sarShortCache = cacheManager.getCache("sar-short");
|
||||
this.sarPermanentCache = cacheManager.getCache("sar-permanent");
|
||||
}
|
||||
private final SarCache sarCache;
|
||||
|
||||
@Override
|
||||
public boolean supports(SarControlParamDTO param) {
|
||||
@ -50,13 +38,10 @@ public class SarControlDisconnectStrategy implements ISarControlStrategy {
|
||||
|
||||
@Override
|
||||
public void sendPost(SarControlDTO sar) {
|
||||
String connectKey = CacheKey.getSarStatus(sar.getIp());
|
||||
if (sarShortCache != null) {
|
||||
sarShortCache.evict(connectKey);
|
||||
}
|
||||
if (sarPermanentCache != null) {
|
||||
sarPermanentCache.evict(sar.getIp());
|
||||
}
|
||||
// 清理短时状态
|
||||
sarCache.removeConnection(sar.getIp()); // ← 从 permanentCache 移除连接标志
|
||||
sarCache.saveStatus(sar.getIp(), null); // ← 等同于清空 shortCache 中的状态
|
||||
log.info("已断开 SAR IP: {},缓存清理完成", sar.getIp());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
package com.zhangy.skyeye.sar.listen;
|
||||
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.sar.dto.SarErrorDTO;
|
||||
import com.zhangy.skyeye.sar.dto.SarStatusPackDTO;
|
||||
import com.zhangy.skyeye.sar.enums.SarErrorTypeEnum;
|
||||
import com.zhangy.skyeye.sar.task.CircularBufferQueue;
|
||||
import com.zhangy.skyeye.sar.task.DiscardOldestPolicyWithLog;
|
||||
import com.zhangy.skyeye.sar.task.PriorityThreadFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -26,6 +25,7 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SarStatusListener extends SarAbstractListener {
|
||||
|
||||
/**
|
||||
@ -50,8 +50,7 @@ public class SarStatusListener extends SarAbstractListener {
|
||||
@Value("${skyeye.sar.udp.status.connect-timeout:15}")
|
||||
private int connectTimeout;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
private final SarCache sarCache;
|
||||
|
||||
@Autowired
|
||||
private JmJobStatusService sarJobStatusService;
|
||||
@ -82,19 +81,13 @@ public class SarStatusListener extends SarAbstractListener {
|
||||
log.warn("状态包校验失败,已丢弃。");
|
||||
return;
|
||||
}
|
||||
Cache sarShortCache = cacheManager.getCache("sar-short");
|
||||
if (sarShortCache == null) {
|
||||
log.error("sar-short 缓存未找到!请检查 CacheConfig");
|
||||
throw new IllegalStateException("sar-short 缓存未找到");
|
||||
}
|
||||
// 错误包 → 回执
|
||||
int errorStatus = packDTO.getErrorPacketStatus();
|
||||
if (errorStatus == 1) {
|
||||
SarErrorDTO info = packDTO.getDeviceErrorInfo();
|
||||
if (info.getErrorPacketType() == SarErrorTypeEnum.RESULT) {
|
||||
log.debug("收到回执包:{}", ip);
|
||||
String controlBackKey = CacheKey.getSarControlBack(ip);
|
||||
sarShortCache.put(controlBackKey, info); // 写入,自动 2s 过期
|
||||
sarCache.saveControlBack(ip, info); // 使用 SarCache,类型安全,自动短期缓存,自动 2s 过期
|
||||
}
|
||||
}
|
||||
// 状态包
|
||||
@ -103,9 +96,8 @@ public class SarStatusListener extends SarAbstractListener {
|
||||
JmSarStatusDTO info = packDTO.getDeviceStatusInfo();
|
||||
log.debug("sar开机状态:{}", info.getIsBoot());
|
||||
sarJobStatusService.update(ip, info);
|
||||
String connectKey = CacheKey.getSarStatus(ip);
|
||||
sarShortCache.put(connectKey, info); // 写入,自动过期
|
||||
sarCache.saveStatus(ip, info); // 使用 SarCache,类型安全,自动短期缓存,自动过期
|
||||
}
|
||||
log.debug("----------------------状态包解析完毕");
|
||||
log.debug("状态包解析完毕");
|
||||
}
|
||||
}
|
||||
@ -5,20 +5,15 @@ import com.zhangy.skyeye.common.extend.util.JsonUtil;
|
||||
import com.zhangy.skyeye.jm.dto.JmJobDTO;
|
||||
import com.zhangy.skyeye.jm.dto.JmSarStatusDTO;
|
||||
import com.zhangy.skyeye.jm.entity.JmJobPayload;
|
||||
import com.zhangy.skyeye.publics.consts.CacheKey;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import com.zhangy.skyeye.cache.sar.SarCache;
|
||||
import com.zhangy.skyeye.sar.control.SarControlContext;
|
||||
import com.zhangy.skyeye.sar.dto.SarControlParamDTO;
|
||||
import com.zhangy.skyeye.sar.enums.SarControlTypeEnum;
|
||||
import com.zhangy.skyeye.sar.service.ISarControlService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.zhangy.skyeye.jm.consts.JmJobModeEnum.CRUISE;
|
||||
@ -32,21 +27,7 @@ import static com.zhangy.skyeye.jm.consts.JmJobModeEnum.CRUISE;
|
||||
public class SarControlServiceImpl implements ISarControlService {
|
||||
|
||||
private final SarControlContext udpSendContext;
|
||||
private final CacheManager cacheManager; // final 字段
|
||||
private Cache sarShortCache;
|
||||
private Cache sarPermanentCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.sarPermanentCache = cacheManager.getCache("sar-permanent");
|
||||
this.sarShortCache = cacheManager.getCache("sar-short");
|
||||
if (sarShortCache == null) {
|
||||
log.error("sar-short cache 未找到!");
|
||||
}
|
||||
if (sarPermanentCache == null) {
|
||||
log.error("sar-permanent cache 未找到!");
|
||||
}
|
||||
}
|
||||
private final SarCache sarCache;
|
||||
|
||||
@Override
|
||||
public void sendUdp(JmJobDTO job) {
|
||||
@ -100,8 +81,10 @@ public class SarControlServiceImpl implements ISarControlService {
|
||||
|
||||
@Override
|
||||
public void turnOn(String ip) {
|
||||
if (Objects.nonNull(sarPermanentCache.get(CacheKey.getSarConnected(ip))) &&
|
||||
Objects.nonNull(sarPermanentCache.get(CacheKey.getSarStatus(ip)))) {
|
||||
// 用领域缓存判断连接和状态
|
||||
boolean connected = sarCache.isConnected(ip);
|
||||
JmSarStatusDTO status = sarCache.getLatestStatus(ip);
|
||||
if (!connected || status == null) {
|
||||
throw new ServiceException("请先加电并连接sar");
|
||||
}
|
||||
SarControlParamDTO param = new SarControlParamDTO(ip, SarControlTypeEnum.TURNON);
|
||||
@ -110,8 +93,10 @@ public class SarControlServiceImpl implements ISarControlService {
|
||||
|
||||
@Override
|
||||
public void endAll(String ip) {
|
||||
if (Objects.nonNull(sarPermanentCache.get(CacheKey.getSarConnected(ip))) &&
|
||||
Objects.nonNull(sarPermanentCache.get(CacheKey.getSarStatus(ip)))) {
|
||||
// 用领域缓存判断连接和状态
|
||||
boolean connected = sarCache.isConnected(ip);
|
||||
JmSarStatusDTO status = sarCache.getLatestStatus(ip);
|
||||
if (!connected || status == null) {
|
||||
throw new ServiceException("请先加电并连接sar");
|
||||
}
|
||||
SarControlParamDTO param = new SarControlParamDTO(ip, SarControlTypeEnum.ENDALL);
|
||||
@ -120,7 +105,6 @@ public class SarControlServiceImpl implements ISarControlService {
|
||||
|
||||
@Override
|
||||
public JmSarStatusDTO getLatestStatus(String ip) {
|
||||
String connectKey = CacheKey.getSarStatus(ip);
|
||||
return CacheUtil.get(sarShortCache, connectKey, JmSarStatusDTO.class);
|
||||
return sarCache.getLatestStatus(ip);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.zhangy.skyeye.sar.service.impl;
|
||||
|
||||
import com.zhangy.skyeye.cache.image.ImageCache;
|
||||
import com.zhangy.skyeye.common.extend.util.MathUtil;
|
||||
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
|
||||
import com.zhangy.skyeye.jm.dto.JmAirlineStatusDTO;
|
||||
@ -10,24 +11,19 @@ import com.zhangy.skyeye.jm.service.JmImageService;
|
||||
import com.zhangy.skyeye.jm.service.JmJobStatusService;
|
||||
import com.zhangy.skyeye.publics.consts.FileTypeEnum;
|
||||
import com.zhangy.skyeye.publics.service.SysFileTypeService;
|
||||
import com.zhangy.skyeye.publics.utils.CacheUtil;
|
||||
import com.zhangy.skyeye.publics.utils.ImageUtil;
|
||||
import com.zhangy.skyeye.publics.utils.OpenCVUtil;
|
||||
import com.zhangy.skyeye.sar.dto.SarBackImageFrameDTO;
|
||||
import com.zhangy.skyeye.sar.service.ISarImageService;
|
||||
import com.zhangy.skyeye.sar.service.SarWsAsyncService;
|
||||
import com.zhangy.skyeye.sar.util.RadarDisplayOptions;
|
||||
import com.zhangy.skyeye.sar.util.SarImageToneAdjuster;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.opencv.core.Mat;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -49,7 +45,7 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
private SarWsAsyncService sarWsAsyncService;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
private ImageCache imageCache;
|
||||
|
||||
// 图片最大宽度,前端说和电脑有关,4096保险点,一般是4096 8192 16384
|
||||
@Value("${skyeye.sar.image.max:4096}")
|
||||
@ -60,16 +56,6 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
// 当前帧号
|
||||
private final String CACHE_FIELD_CURR_FRAME_NO = "currFrameNo";
|
||||
|
||||
private Cache joinStateCache;
|
||||
|
||||
@PostConstruct
|
||||
public void initCache() {
|
||||
joinStateCache = cacheManager.getCache("image-join-state");
|
||||
if (joinStateCache == null) {
|
||||
log.error("缓存 image-join-state 未找到,请检查 CacheConfig");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基准图像信息
|
||||
*
|
||||
@ -87,15 +73,15 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
base = new JmImage();
|
||||
base.setImageNo(1);
|
||||
// 存起始帧号
|
||||
joinStateCache.put(cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, frameNo);
|
||||
imageCache.put(cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, frameNo);
|
||||
return base;
|
||||
}
|
||||
// 情况2:如果最后一张还能拼图,则直接返回继续拼
|
||||
JmImage last = imageList.get(imageList.size() - 1);
|
||||
Integer startFrameNo = CacheUtil.get(joinStateCache, cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, Integer.class);
|
||||
Integer startFrameNo = imageCache.get(cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, Integer.class);
|
||||
int currWidth = startFrameNo == null ? 0 : singleWidth * (frameNo - startFrameNo + 1);
|
||||
int surplusNum = (IMG_MAX_WITH - currWidth) / singleWidth; // 还可以拼图片数
|
||||
Integer baseNo = CacheUtil.get(joinStateCache, cachePrefix + ":" + CACHE_FIELD_CURR_FRAME_NO, Integer.class);
|
||||
Integer baseNo = imageCache.get(cachePrefix + ":" + CACHE_FIELD_CURR_FRAME_NO, Integer.class);
|
||||
|
||||
if (startFrameNo == null || currWidth < IMG_MAX_WITH ||
|
||||
baseNo == null || (frameNo - baseNo + 1 <= surplusNum)) {
|
||||
@ -105,7 +91,7 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
// 情况3:已经拼接到最大数量,或者当前图+填充数量超过允许拼接数量,创建新图像文件
|
||||
log.info("当前宽度:{} > {} 重新拼接,当前帧号{}作为首帧", currWidth, IMG_MAX_WITH, frameNo);
|
||||
base = new JmImage();
|
||||
joinStateCache.put(cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, frameNo);
|
||||
imageCache.put(cachePrefix + ":" + CACHE_FIELD_START_FRAME_NO, frameNo);
|
||||
base.setImageNo(last.getImageNo() + 1);
|
||||
return base;
|
||||
}
|
||||
@ -173,7 +159,7 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
System.out.println("帧:" + frameNo);
|
||||
|
||||
// 4.保存基准图(同步),用于下次拼接
|
||||
Integer baseNo = CacheUtil.get(joinStateCache, "jmImgJoin-" + airlineExecId + ":" + CACHE_FIELD_CURR_FRAME_NO, Integer.class);
|
||||
Integer baseNo = imageCache.get("jmImgJoin-" + airlineExecId + ":" + CACHE_FIELD_CURR_FRAME_NO, Integer.class);
|
||||
boolean lostImage = baseNo != null && (frameNo - baseNo > 1); // 判断是否丢图
|
||||
String basePath = sysFileTypeService.getAbsolutePath(FileTypeEnum.SAR_IMAGE_LOW, jobExecId,
|
||||
airlineExecId + "-" + base.getImageNo() + "-base.png");
|
||||
@ -186,7 +172,7 @@ public class SarImageServiceImpl implements ISarImageService {
|
||||
}
|
||||
|
||||
//modCoord(imageFrame, lostImage, currAirline);
|
||||
joinStateCache.put("jmImgJoin-" + airlineExecId + ":" + CACHE_FIELD_CURR_FRAME_NO, frameNo);
|
||||
imageCache.put("jmImgJoin-" + airlineExecId + ":" + CACHE_FIELD_CURR_FRAME_NO, frameNo);
|
||||
// ### 亮度调整,用于可靠udp版本图像,固定使用系数0.5
|
||||
// 拆分多张图片,去掉自适应调整
|
||||
if (IMG_MAX_WITH > 20000) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user