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