list = weatherDailyDataDao.selectSummarizeByMonthDay(
+ stationIds,
+ startTime.getMonthValue(),
+ startTime.getDayOfMonth(),
+ startTime.getYear(),
+ endTime.getYear());
return BeanUtil.copyToList(list, DailyWeatherSummarizeDto.class);
}
diff --git a/system-admin/src/main/java/com/weather/modules/weather/dailydata/task/WeatherSummarizeCacheTask.java b/system-admin/src/main/java/com/weather/modules/weather/dailydata/task/WeatherSummarizeCacheTask.java
new file mode 100644
index 0000000..bf4eb91
--- /dev/null
+++ b/system-admin/src/main/java/com/weather/modules/weather/dailydata/task/WeatherSummarizeCacheTask.java
@@ -0,0 +1,65 @@
+package com.weather.modules.weather.dailydata.task;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.weather.common.redis.RedisKeys;
+import com.weather.common.redis.RedisUtils;
+import com.weather.modules.job.task.ITask;
+import com.weather.modules.weather.dailydata.dao.WeatherDailyDataDao;
+import com.weather.modules.weather.dailydata.dto.DailyWeatherSummarizeDto;
+import com.weather.modules.weather.dailydata.entity.WeatherDailyDataEntity;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 天气汇总缓存预热任务
+ *
+ * 每日凌晨 1:00 执行,将历年当月-当日的气象数据
+ * 按站点分组写入 Redis,供 export-sum 接口查询。
+ *
+ * @author 2333 123
+ * @since 1.0.0 2026-06-24
+ */
+@Slf4j
+@Component("weatherSummarizeCacheTask")
+public class WeatherSummarizeCacheTask implements ITask {
+
+ @Resource
+ private WeatherDailyDataDao weatherDailyDataDao;
+
+ @Resource
+ private RedisUtils redisUtils;
+
+ @Override
+ public void run(String params) {
+ LocalDate today = LocalDate.now();
+ int month = today.getMonthValue();
+ int day = today.getDayOfMonth();
+
+ log.info("开始刷新天气汇总缓存,日期: {}-{}", month, day);
+
+ try {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.apply("MONTH(observe_date) = {0} AND DAY(observe_date) = {1}", month, day);
+
+ List list = weatherDailyDataDao.selectSummarizeList(wrapper);
+
+ Map> grouped = list.stream()
+ .map(e -> BeanUtil.copyProperties(e, DailyWeatherSummarizeDto.class))
+ .collect(Collectors.groupingBy(dto -> String.valueOf(dto.getStationId())));
+
+ String key = RedisKeys.getWeatherSummarizeKey(month, day);
+ redisUtils.set(key, grouped, RedisUtils.NOT_EXPIRE);
+
+ log.info("天气汇总缓存刷新完成,共 {} 条记录,{} 个站点", list.size(), grouped.size());
+ } catch (Exception e) {
+ log.error("天气汇总缓存刷新失败", e);
+ }
+ }
+}
diff --git a/system-admin/src/main/java/com/weather/modules/weather/filescan/FileScanStartupRunner.java b/system-admin/src/main/java/com/weather/modules/weather/filescan/FileScanStartupRunner.java
index 732c282..7787b7b 100644
--- a/system-admin/src/main/java/com/weather/modules/weather/filescan/FileScanStartupRunner.java
+++ b/system-admin/src/main/java/com/weather/modules/weather/filescan/FileScanStartupRunner.java
@@ -7,7 +7,9 @@ import com.weather.modules.sys.entity.SysDeptEntity;
import com.weather.modules.sys.service.SysParamsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.io.IOException;
@@ -15,18 +17,33 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@AllArgsConstructor
-public class FileScanStartupRunner implements CommandLineRunner {
+public class FileScanStartupRunner {
+
+ /**
+ * 启动后延迟扫描时间(秒),给应用留出充分的初始化时间
+ */
+ private static final long STARTUP_DELAY_SECONDS = 30;
private final SysParamsService sysParamsService;
private final SysDeptDao sysDeptDao;
private final FileWatchServiceManager fileWatchServiceManager;
- @Override
- public void run(String... args) {
+ @Async
+ @EventListener(ApplicationReadyEvent.class)
+ public void onApplicationReady() {
+ log.info("应用已启动,{} 秒后开始文件扫描目录初始化...", STARTUP_DELAY_SECONDS);
+ try {
+ TimeUnit.SECONDS.sleep(STARTUP_DELAY_SECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("文件扫描延迟等待被中断,直接开始初始化");
+ }
+
String rootPath = sysParamsService.getValue(Constant.FILE_SCAN_ROOT_PATH);
if (StrUtil.isBlank(rootPath)) {
log.warn("FILE_SCAN_ROOT_PATH 未配置,跳过文件扫描目录初始化");
diff --git a/system-admin/src/main/resources/application-dev.yml b/system-admin/src/main/resources/application-dev.yml
index 5ce6347..bf2a777 100644
--- a/system-admin/src/main/resources/application-dev.yml
+++ b/system-admin/src/main/resources/application-dev.yml
@@ -6,26 +6,6 @@ spring:
url: jdbc:mysql://localhost:3306/weather_data_system?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
username: root
password: root
- #达梦8
-# driver-class-name: dm.jdbc.driver.DmDriver
-# url: jdbc:dm://192.168.10.10:5236/renren_security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
-# username: renren_security
-# password: 12345678
- # #Oracle
- # driver-class-name: oracle.jdbc.OracleDriver
- # url: jdbc:oracle:thin:@192.168.10.10:1521:xe
- # username: renren_security
- # password: 123456
- # #SQLServer
- # driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
- # url: jdbc:sqlserver://localhost:1433;DatabaseName=renren_security
- # username: sa
- # password: 123456
- # #postgresql
- # driver-class-name: org.postgresql.Driver
- # url: jdbc:postgresql://192.168.10.10:5432/postgres
- # username: postgres
- # password: 123456
initial-size: 10
max-active: 100
min-idle: 10
diff --git a/system-admin/src/main/resources/application.yml b/system-admin/src/main/resources/application.yml
index cc42588..f89170c 100644
--- a/system-admin/src/main/resources/application.yml
+++ b/system-admin/src/main/resources/application.yml
@@ -40,7 +40,7 @@ spring:
data:
redis:
database: 0
- host: 192.168.10.10
+ host: 127.0.0.1
port: 6379
password: # 密码(默认为空)
timeout: 6000ms # 连接超时时长(毫秒)
@@ -54,7 +54,7 @@ spring:
# 是否开启redis缓存 true开启 false关闭
project-options:
redis:
- open: false
+ open: true
#mybatis
mybatis-plus:
diff --git a/system-admin/src/main/resources/mapper/dailyweather/WeatherDailyDataDao.xml b/system-admin/src/main/resources/mapper/dailyweather/WeatherDailyDataDao.xml
index ee6af68..14319e8 100644
--- a/system-admin/src/main/resources/mapper/dailyweather/WeatherDailyDataDao.xml
+++ b/system-admin/src/main/resources/mapper/dailyweather/WeatherDailyDataDao.xml
@@ -42,6 +42,19 @@
ORDER BY station_id, observe_date
+
+
INSERT INTO weather_daily_data (
id, station_id, observe_date,
diff --git a/system-api/Dockerfile b/system-api/Dockerfile
index 251b7fc..f99b91a 100644
--- a/system-api/Dockerfile
+++ b/system-api/Dockerfile
@@ -1,7 +1,23 @@
-FROM java:8
+FROM eclipse-temurin:17-jre-alpine
+
+LABEL maintainer="weather-data"
+LABEL description="Weather Data System - API Service"
+
+RUN apk add --no-cache tzdata curl && \
+ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
+ echo "Asia/Shanghai" > /etc/timezone
+
+WORKDIR /app
+
EXPOSE 8081
-VOLUME /tmp
-ADD renren-api.jar /app.jar
-RUN bash -c 'touch /app.jar'
-ENTRYPOINT ["java","-jar","/app.jar"]
+ARG JAR_FILE=target/system-api.jar
+COPY ${JAR_FILE} /app/app.jar
+
+ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -Djava.security.egd=file:/dev/./urandom"
+ENV SPRING_PROFILES_ACTIVE=prod
+
+HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \
+ CMD curl -f http://localhost:8081/renren-api/actuator/health || exit 1
+
+ENTRYPOINT exec java ${JAVA_OPTS} -jar /app/app.jar
diff --git a/system-common/src/main/java/com/weather/common/aspect/RedisAspect.java b/system-common/src/main/java/com/weather/common/aspect/RedisAspect.java
index 1de2bed..0199253 100644
--- a/system-common/src/main/java/com/weather/common/aspect/RedisAspect.java
+++ b/system-common/src/main/java/com/weather/common/aspect/RedisAspect.java
@@ -23,7 +23,7 @@ public class RedisAspect {
/**
* 是否开启redis缓存 true开启 false关闭
*/
- @Value("${weather.redis.open: false}")
+ @Value("${project-options.redis.open: false}")
private boolean open;
@Around("execution(* com.weather.common.redis.RedisUtils.*(..))")
diff --git a/system-common/src/main/java/com/weather/common/redis/RedisKeys.java b/system-common/src/main/java/com/weather/common/redis/RedisKeys.java
index b1882e5..7c4ba5b 100644
--- a/system-common/src/main/java/com/weather/common/redis/RedisKeys.java
+++ b/system-common/src/main/java/com/weather/common/redis/RedisKeys.java
@@ -55,4 +55,18 @@ public class RedisKeys {
public static String getUserPermissionsKey(Long userId){
return "sys:user:permissions:" + userId;
}
+
+ /**
+ * 天气汇总缓存Key(按站点分组,月-日维度)
+ */
+ public static String getWeatherSummarizeKey(int month, int day) {
+ return "weather:summarize:" + month + ":" + day;
+ }
+
+ /**
+ * 天气汇总缓存匹配模式
+ */
+ public static String getWeatherSummarizePattern() {
+ return "weather:summarize:*";
+ }
}
diff --git a/system-common/src/main/java/com/weather/common/redis/RedisUtils.java b/system-common/src/main/java/com/weather/common/redis/RedisUtils.java
index 0cb85a1..cf41b11 100644
--- a/system-common/src/main/java/com/weather/common/redis/RedisUtils.java
+++ b/system-common/src/main/java/com/weather/common/redis/RedisUtils.java
@@ -116,4 +116,23 @@ public class RedisUtils {
public Object rightPop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
+
+ /**
+ * 按模式删除缓存
+ * @param pattern 匹配模式,如 "weather:summarize:*"
+ */
+ public void deleteByPattern(String pattern) {
+ java.util.Set keys = redisTemplate.keys(pattern);
+ if (keys != null && !keys.isEmpty()) {
+ redisTemplate.delete(keys);
+ }
+ }
+
+ /**
+ * 判断缓存是否存在
+ */
+ public boolean exists(String key) {
+ Boolean result = redisTemplate.hasKey(key);
+ return Boolean.TRUE.equals(result);
+ }
}