From 13805a065d1fb131424a3cb7e07203d1a2c3f214 Mon Sep 17 00:00:00 2001
From: shiyi <shi_yee@outlook.com>
Date: Wed, 12 Jun 2024 16:08:27 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=EF=BC=9A?=
 =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E3=80=81=E5=AF=BC=E5=85=A5=E3=80=81=E6=B8=85?=
 =?UTF-8?q?=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weather/WeatherServiceApplication.java    |  3 +
 .../htfp/weather/download/GfsDataConfig.java  | 13 ++--
 .../griddata/operation/GfsDataImport.java     |  4 +-
 .../weather/schedule/GridDataProcessor.java   | 64 +++++++++++++++----
 .../web/controller/ConfigController.java      | 18 +++---
 .../controller/ControllerExceptionAdvice.java |  6 +-
 .../controller/UpperWeatherController.java    |  6 +-
 .../{AppExcpetion.java => AppException.java}  |  8 +--
 .../web/pojo/request/PlaneRequest.java        |  6 +-
 .../htfp/weather/web/service/FileService.java |  8 +--
 .../web/service/GfsDataServiceImpl.java       | 48 +++++++-------
 .../service/surfaceapi/CaiYunServiceImpl.java | 14 ++--
 .../service/surfaceapi/HeFengServiceImpl.java |  8 +--
 13 files changed, 122 insertions(+), 84 deletions(-)
 rename weather-service/src/main/java/com/htfp/weather/web/exception/{AppExcpetion.java => AppException.java} (64%)

diff --git a/weather-service/src/main/java/com/htfp/weather/WeatherServiceApplication.java b/weather-service/src/main/java/com/htfp/weather/WeatherServiceApplication.java
index 42516f8..90797fe 100644
--- a/weather-service/src/main/java/com/htfp/weather/WeatherServiceApplication.java
+++ b/weather-service/src/main/java/com/htfp/weather/WeatherServiceApplication.java
@@ -4,12 +4,15 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
+import java.util.TimeZone;
+
 @EnableScheduling
 @SpringBootApplication
 public class WeatherServiceApplication {
 
     public static void main(String[] args) {
         try {
+            TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
             SpringApplication.run(WeatherServiceApplication.class, args);
         } catch (Exception e) {
             throw new RuntimeException(e);
diff --git a/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java b/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java
index 84c0349..5b9a964 100644
--- a/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java
+++ b/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.htfp.weather.info.GfsDownloadVariableEnum;
 import com.htfp.weather.info.GfsLevelsEnum;
 import com.htfp.weather.utils.JSONUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.NoSuchFileException;
 import java.util.ArrayList;
-import java.util.Objects;
 
 /**
  * @Author : shiyi
@@ -80,10 +79,10 @@ public class GfsDataConfig {
     public void valid() {
         // TODO 2024/4/21: 校验
         if (minLon >= maxLon) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, "最小经度必须小于最大经度");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, "最小经度必须小于最大经度");
         }
         if (minLat >= maxLat) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, "最小纬度必须小于最大纬度度");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, "最小纬度必须小于最大纬度度");
         }
         ArrayList<String> wrongVariables = new ArrayList<>();
         ArrayList<Integer> wrongLevels = new ArrayList<>();
@@ -93,7 +92,7 @@ public class GfsDataConfig {
             }
         }
         if (!wrongVariables.isEmpty()) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, " variables = " +wrongVariables + "非 GfsLevelsEnum 枚举值");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, " variables = " +wrongVariables + "非 GfsLevelsEnum 枚举值");
         }
 
         for (Integer level : pressureLevels) {
@@ -102,7 +101,7 @@ public class GfsDataConfig {
             }
         }
         if (!wrongLevels.isEmpty()) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, " pressureLevels = " +wrongLevels + "非 GfsLevelsEnum 枚举值");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, " pressureLevels = " +wrongLevels + "非 GfsLevelsEnum 枚举值");
         }
     }
     @PostConstruct
@@ -148,7 +147,7 @@ public class GfsDataConfig {
         if (!destDir.exists()) {
             boolean mkdirs = destDir.mkdirs();
             if (!mkdirs) {
-                throw new AppExcpetion(ErrorCode.CONFIG_ERROR, "目录创建失败: " + saveRoot);
+                throw new AppException(ErrorCode.CONFIG_ERROR, "目录创建失败: " + saveRoot);
             }
         }
         JSONUtils.pojo2jsonFile(this, filePath);
diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataImport.java b/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataImport.java
index 02ddf1c..7186ba7 100644
--- a/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataImport.java
+++ b/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataImport.java
@@ -10,7 +10,7 @@ import com.htfp.weather.griddata.common.GfsVariableIsobaricEnum;
 import com.htfp.weather.griddata.common.TableConfig;
 import com.htfp.weather.info.Constant;
 import com.htfp.weather.utils.MeteoUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import lombok.Data;
 import lombok.Getter;
@@ -101,7 +101,7 @@ public class GfsDataImport extends BaseTableOperation {
         long start = System.currentTimeMillis();
         List<String> fileList = getFiles(refTime);
         if (CollectionUtils.isEmpty(fileList)) {
-            throw new AppExcpetion(ErrorCode.NO_NC_OR_GRIB_FILES);
+            throw new AppException(ErrorCode.NO_NC_OR_GRIB_FILES);
         }
         String dataSetId = refTime.format(DateTimeFormatter.ofPattern(Constant.DATA_SET_ID_FORMAT_STRING));
         List<String> fileVariables = getFileVariables(tableConfig.variableList);
diff --git a/weather-service/src/main/java/com/htfp/weather/schedule/GridDataProcessor.java b/weather-service/src/main/java/com/htfp/weather/schedule/GridDataProcessor.java
index 7592d0c..67d89dc 100644
--- a/weather-service/src/main/java/com/htfp/weather/schedule/GridDataProcessor.java
+++ b/weather-service/src/main/java/com/htfp/weather/schedule/GridDataProcessor.java
@@ -5,11 +5,10 @@ import com.htfp.weather.download.GfsDataConfig;
 import com.htfp.weather.download.GfsDownloader;
 import com.htfp.weather.griddata.operation.GfsDataImport;
 import com.htfp.weather.info.Constant;
-import com.htfp.weather.web.exception.AppExcpetion;
-import com.htfp.weather.web.service.FileService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.springframework.context.annotation.DependsOn;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -20,6 +19,7 @@ import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @Author : shiyi
@@ -37,25 +37,61 @@ public class GridDataProcessor {
     @Resource
     GfsDataConfig gfsDataConfig;
 
-
+    @Scheduled(cron = "0 0 0,8,12,18 * * ?")
     public void dailyDataProcess() throws Exception {
-        gfsDownloader.iniTimeSetting();
-        OffsetDateTime refTime = gfsDownloader.getRefTime();
-        List<FileInfo> fileInfoList = gfsDownloader.getFilesInfo();
-        // if (allComplete) {
+        if (download()) {
+            importToTableStore();
+        }
+        clearExpiredData();
+    }
+
+    private boolean importToTableStore() throws Exception {
         try {
-            gfsDataImport.importData(refTime)
-        } catch (AppExcpetion e) {
-            log.info("导入数据失败");
+            OffsetDateTime refTime = gfsDownloader.getRefTime();
+            log.info("[schedule-start] 开始将数据导入数据库, 起报时间: {}", refTime);
+            List<GfsDataImport.ImportResult> importResults = gfsDataImport.importData(refTime);
+            List<GfsDataImport.ImportResult> failedList = importResults.stream().filter(result -> !result.isSuccess()).collect(Collectors.toList());
+            if (!failedList.isEmpty()) {
+                log.error("[schedule-end] 气象数据导入数据库失败, 文件列表: {} ", failedList);
+                emailReport();
+                return false;
+            }
+            log.info("[schedule-end] 气象数据导入数据库成功");
+            return true;
+        } catch (Exception e) {
+            log.error("[schedule-end] 气象数据导入数据库失败", e);
+            return false;
+        }
+    }
 
+    private boolean download() {
+        try {
+            log.info("[schedule-start] 开始下载气象数据");
+            gfsDownloader.iniTimeSetting();
+            List<FileInfo> fileInfoList = gfsDownloader.getFilesInfo();
+            List<FileInfo> finishedList = gfsDownloader.downloadAll(fileInfoList);
+            List<FileInfo> failedList = finishedList.stream().filter(fileInfo -> !fileInfo.isDownloadSuccess()).collect(Collectors.toList());
+            if (!failedList.isEmpty()) {
+                log.error("[schedule] 下载失败文件列表: {}", failedList);
+                emailReport();
+                return false;
+            }
+            log.info("[schedule-end] 下载气象数据成功");
+            return true;
+        } catch (RuntimeException e) {
+            log.error("[schedule-end] 下载气象数据失败", e);
+            return false;
         }
     }
 
+    private void emailReport() {
+    }
+
     public void clearExpiredData() {
-        // String dataFolder = refTime.format(DateTimeFormatter.ofPattern(Constant.DATA_FOLDER_STRING));
+        log.info("[schedule-start] 开始清理过期数据");
         File dataDir = new File(gfsDataConfig.getSaveRoot());
         if (!dataDir.exists()) {
-            log.warn("文件夹 {} 不存在", dataDir);
+            log.warn("[schedule] 文件夹 {} 不存在, 无法清理数据", dataDir);
             return;
         }
         OffsetDateTime now = OffsetDateTime.now();
@@ -64,9 +100,9 @@ public class GridDataProcessor {
             if (refTime.isBefore(now.minusDays(3))) {
                 try {
                     FileUtils.deleteDirectory(subDir);
-                    log.info("删除过期数据文件夹成功: {}", subDir.getName());
+                    log.info("[schedule-end] 删除过期数据文件夹成功: {}", subDir.getName());
                 } catch (IOException e) {
-                    log.info("删除过期数据文件夹失败: {}", subDir.getName());
+                    log.info("[schedule-end] 删除过期数据文件夹失败: {}", subDir.getName());
                 }
             }
         }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/controller/ConfigController.java b/weather-service/src/main/java/com/htfp/weather/web/controller/ConfigController.java
index 36159fe..029ce84 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/controller/ConfigController.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/controller/ConfigController.java
@@ -8,7 +8,7 @@ import com.htfp.weather.griddata.operation.GfsDataImport;
 import com.htfp.weather.griddata.operation.GfsDataImport.ImportResult;
 import com.htfp.weather.info.Constant;
 import com.htfp.weather.utils.DateTimeUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.request.GfsConfigUpdate;
 import com.htfp.weather.web.pojo.request.TableConfigUpdate;
@@ -52,7 +52,7 @@ public class ConfigController {
 
     private void validSecret(String secret) {
         if (StringUtils.isEmpty(secret) || !SECRET.equals(secret)) {
-            throw new AppExcpetion(ErrorCode.SECRET_ERROR);
+            throw new AppException(ErrorCode.SECRET_ERROR);
         }
     }
 
@@ -73,13 +73,13 @@ public class ConfigController {
         TableConfig updateConfig = request.getConfig();
         validSecret(secret);
         if (updateConfig == null) {
-            throw new AppExcpetion(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
+            throw new AppException(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
         }
         updateConfig.valid();
         try {
             tableConfig.writeConfig(updateConfig);
         } catch (IOException e) {
-            throw new AppExcpetion(ErrorCode.CONFIG_ERROR, e);
+            throw new AppException(ErrorCode.CONFIG_ERROR, e);
         }
         return Result.success();
     }
@@ -101,13 +101,13 @@ public class ConfigController {
         GfsDataConfig updateConfig = request.getConfig();
         validSecret(secret);
         if (updateConfig == null) {
-            throw new AppExcpetion(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
+            throw new AppException(ErrorCode.CONFIG_ERROR, "配置文件不能为空");
         }
         updateConfig.valid();
         try {
             gfsDataConfig.writeConfig(updateConfig);
         } catch (IOException e) {
-            throw new AppExcpetion(ErrorCode.CONFIG_ERROR, e);
+            throw new AppException(ErrorCode.CONFIG_ERROR, e);
         }
         return Result.success();
     }
@@ -134,7 +134,7 @@ public class ConfigController {
             } else {
                 return new Result(false, ErrorCode.DOWNLOAD_ERROR.getCode(), ErrorCode.DOWNLOAD_ERROR.getMsg() + ":下载未全部完成", data);
             }
-        } catch (AppExcpetion e) {
+        } catch (AppException e) {
             return Result.error(ErrorCode.DOWNLOAD_START_ERROR, e.getMessage());
         }
     }
@@ -162,7 +162,7 @@ public class ConfigController {
                 }
             }
             return Result.error(ErrorCode.QUERY_TIME_ERROR, ": 请选择当前时间之后24小时范围内的时刻");
-        } catch (AppExcpetion e) {
+        } catch (AppException e) {
             return Result.error(ErrorCode.DOWNLOAD_START_ERROR, e.getMessage());
         }
     }
@@ -187,7 +187,7 @@ public class ConfigController {
             } else {
                 return new Result(false, ErrorCode.TABLESTORE_IMPORT_ERROR.getCode(), ErrorCode.TABLESTORE_IMPORT_ERROR.getMsg() + ": 数据导入未全部完成", data);
             }
-        } catch (AppExcpetion e) {
+        } catch (AppException e) {
             return Result.error(e.getErrorCode());
         } catch (Exception e) {
             return Result.error(e);
diff --git a/weather-service/src/main/java/com/htfp/weather/web/controller/ControllerExceptionAdvice.java b/weather-service/src/main/java/com/htfp/weather/web/controller/ControllerExceptionAdvice.java
index 180e017..95b3f15 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/controller/ControllerExceptionAdvice.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/controller/ControllerExceptionAdvice.java
@@ -1,6 +1,6 @@
 package com.htfp.weather.web.controller;
 
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.response.Result;
 import org.springframework.validation.BindException;
@@ -28,8 +28,8 @@ public class ControllerExceptionAdvice {
     //     return Result.error(e);
     // }
 
-    @ExceptionHandler({AppExcpetion.class})
-    public Result appExceptionHandler(AppExcpetion e) {
+    @ExceptionHandler({AppException.class})
+    public Result appExceptionHandler(AppException e) {
         return Result.error(e.getErrorCode(), e.getMessage());
     }
 }
\ No newline at end of file
diff --git a/weather-service/src/main/java/com/htfp/weather/web/controller/UpperWeatherController.java b/weather-service/src/main/java/com/htfp/weather/web/controller/UpperWeatherController.java
index 0ed3599..98731ac 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/controller/UpperWeatherController.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/controller/UpperWeatherController.java
@@ -1,7 +1,7 @@
 package com.htfp.weather.web.controller;
 
 import com.htfp.weather.utils.DateTimeUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.request.*;
 import com.htfp.weather.web.pojo.response.*;
@@ -83,7 +83,7 @@ public class UpperWeatherController {
                 latitudeList.add(latitude);
                 longitudeList.add(longitude);
             } else {
-                throw new AppExcpetion(ErrorCode.MULTI_INDEX_ERROR);
+                throw new AppException(ErrorCode.MULTI_INDEX_ERROR);
             }
         }
         int level = multiPointsRequest.getLevel().intValue();
@@ -102,7 +102,7 @@ public class UpperWeatherController {
                 latitudeList.add(latitude);
                 longitudeList.add(longitude);
             } else {
-                throw new AppExcpetion(ErrorCode.MULTI_INDEX_ERROR);
+                throw new AppException(ErrorCode.MULTI_INDEX_ERROR);
             }
         }
         int level = multiPointsRequest.getLevel().intValue();
diff --git a/weather-service/src/main/java/com/htfp/weather/web/exception/AppExcpetion.java b/weather-service/src/main/java/com/htfp/weather/web/exception/AppException.java
similarity index 64%
rename from weather-service/src/main/java/com/htfp/weather/web/exception/AppExcpetion.java
rename to weather-service/src/main/java/com/htfp/weather/web/exception/AppException.java
index f27551c..27697bd 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/exception/AppExcpetion.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/exception/AppException.java
@@ -5,20 +5,20 @@ package com.htfp.weather.web.exception;
  * @Date : 2024/4/16 17:21
  * @Description : 自定义异常
  */
-public class AppExcpetion extends RuntimeException{
+public class AppException extends RuntimeException{
     ErrorCode errorCode;
 
     public ErrorCode getErrorCode() {
         return errorCode;
     }
-    public AppExcpetion(ErrorCode errorCode) {
+    public AppException(ErrorCode errorCode) {
         this.errorCode = errorCode;
     }
-    public AppExcpetion(ErrorCode errorCode, String message) {
+    public AppException(ErrorCode errorCode, String message) {
         super(message);
         this.errorCode = errorCode;
     }
-    public AppExcpetion(ErrorCode errorCode, Throwable e) {
+    public AppException(ErrorCode errorCode, Throwable e) {
         super(e);
         this.errorCode = errorCode;
     }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/PlaneRequest.java b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/PlaneRequest.java
index c041bb4..19d8285 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/PlaneRequest.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/PlaneRequest.java
@@ -3,7 +3,7 @@ package com.htfp.weather.web.pojo.request;
 import com.htfp.weather.griddata.common.GfsVariableIsobaricEnum;
 import com.htfp.weather.info.Constant;
 import com.htfp.weather.info.GfsLevelsEnum;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.valid.DateTimeStr;
 import com.htfp.weather.web.valid.EnumValid;
@@ -55,10 +55,10 @@ public class PlaneRequest {
     public void valid() {
         // TODO 2024/4/21: 校验
         if (minLon >= maxLon) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, "最小经度必须小于最大经度");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, "最小经度必须小于最大经度");
         }
         if (minLat >= maxLat) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, "最小纬度必须小于最大纬度度");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, "最小纬度必须小于最大纬度度");
         }
     }
 }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/FileService.java b/weather-service/src/main/java/com/htfp/weather/web/service/FileService.java
index 68e3bfe..d24a724 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/FileService.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/FileService.java
@@ -1,6 +1,6 @@
 package com.htfp.weather.web.service;
 
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.response.FileInfo;
 import org.apache.commons.io.FileUtils;
@@ -21,7 +21,7 @@ public class FileService {
 
     public List<FileInfo>  getFileList(File dataDir){
         if (!dataDir.exists() || !dataDir.isDirectory()) {
-            throw new AppExcpetion(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
+            throw new AppException(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
         }
         List<FileInfo> fileInfoList = new ArrayList<>();
         File[] files = dataDir.listFiles();
@@ -50,14 +50,14 @@ public class FileService {
 
     public void deleteFile(File file) throws IOException {
         if (file == null || !file.exists()) {
-            throw new AppExcpetion(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
+            throw new AppException(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
         }
         FileUtils.delete(file);
     }
 
     public void deleteDir(File dir) throws IOException {
         if (!dir.exists() || !dir.isDirectory()) {
-            throw new AppExcpetion(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
+            throw new AppException(ErrorCode.DATA_FILE_OR_DIR_NOT_EXISTS);
         }
         FileUtils.deleteDirectory(dir);
     }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java b/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
index 834f5bb..20e80f6 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
@@ -13,7 +13,7 @@ import com.htfp.weather.info.Constant;
 import com.htfp.weather.info.GfsLevelsEnum;
 import com.htfp.weather.utils.DateTimeUtils;
 import com.htfp.weather.utils.NdArrayUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.response.NowWeatherStatus;
 import com.htfp.weather.web.pojo.response.PlaneResponse;
@@ -65,14 +65,14 @@ public class GfsDataServiceImpl implements IDataService {
         String targetVariable = GfsVariableIsobaricEnum.getGfsVariableName(variableName);
 
         if (targetVariable == null) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, variableName + "变量在数据库中不存在");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, variableName + "变量在数据库中不存在");
         }
 
         GridDataSetMeta lastGridDataSetMeta = null;
         try {
             lastGridDataSetMeta = queryMeta.getLastGridDataSetMeta();
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
+            throw new AppException(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
         }
         int iTime = getTargetTimeIndex(targetTime, lastGridDataSetMeta);
         int iLat = getLatitudeIndex(latitude);
@@ -102,7 +102,7 @@ public class GfsDataServiceImpl implements IDataService {
         try {
             lastGridDataSetMeta = queryMeta.getLastGridDataSetMeta();
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
+            throw new AppException(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
         }
         Map<String, List> params = getFutureTimeIndexList(lastGridDataSetMeta);
         List<Integer> iTimeList = params.get("iTimeList");
@@ -141,7 +141,7 @@ public class GfsDataServiceImpl implements IDataService {
         try {
             lastGridDataSetMeta = queryMeta.getLastGridDataSetMeta();
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.DATA_SET_EMPTY, ": " + e.getMessage());
+            throw new AppException(ErrorCode.DATA_SET_EMPTY, ": " + e.getMessage());
         }
         int iTime = getTargetTimeIndex(OffsetDateTime.now(), lastGridDataSetMeta);
         int iLat = getLatitudeIndex(latitude);
@@ -176,10 +176,10 @@ public class GfsDataServiceImpl implements IDataService {
         try {
             lastGridDataSetMeta = queryMeta.getLastGridDataSetMeta();
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.DATA_SET_EMPTY, ": " + e.getMessage());
+            throw new AppException(ErrorCode.DATA_SET_EMPTY, ": " + e.getMessage());
         }
         if (latitude.size() != longitude.size()) {
-            throw new AppExcpetion(ErrorCode.INDEX_SIZE_ERROR, ": 经纬度数组大小不一致");
+            throw new AppException(ErrorCode.INDEX_SIZE_ERROR, ": 经纬度数组大小不一致");
         }
         int pointSize = latitude.size();
         List<String> variableNames = getVariableNamesInDatabase(level);
@@ -264,13 +264,13 @@ public class GfsDataServiceImpl implements IDataService {
         }
 
         if (targetVariable == null) {
-            throw new AppExcpetion(ErrorCode.VALIDATE_ERROR, variableName + "变量在数据库中不存在");
+            throw new AppException(ErrorCode.VALIDATE_ERROR, variableName + "变量在数据库中不存在");
         }
         GridDataSetMeta lastGridDataSetMeta = null;
         try {
             lastGridDataSetMeta = queryMeta.getLastGridDataSetMeta();
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
+            throw new AppException(ErrorCode.DATA_SET_EMPTY, ": e.getMessage()");
         }
 
         int iTime = getTargetTimeIndex(targetTime, lastGridDataSetMeta);
@@ -388,7 +388,7 @@ public class GfsDataServiceImpl implements IDataService {
                 variableNameInApi = GfsVariableIsobaricEnum.getVariableNameInApi(variableNameInFile);
             }
             if (variableNameInApi == null) {
-                throw new AppExcpetion(ErrorCode.NO_SUCH_VARIABLE);
+                throw new AppException(ErrorCode.NO_SUCH_VARIABLE);
             }
             Grid4D grid4D = entry.getValue(); Index4D index = new Index4D(grid4D.getShape());
             try {
@@ -396,10 +396,10 @@ public class GfsDataServiceImpl implements IDataService {
                 Method method =  aClass.getDeclaredMethod(setMethodName, aClass.getDeclaredField(variableNameInApi).getType());
                 method.invoke(result, grid4D.toArray().getFloat(index.set(0, iLevInGrid, iLatInGrid, iLonInGrid)));
             } catch (ReflectiveOperationException e) {
-                throw new AppExcpetion(ErrorCode.NO_SUCH_VARIABLE, e);
+                throw new AppException(ErrorCode.NO_SUCH_VARIABLE, e);
             } catch (Exception e) {
                 e.printStackTrace();
-                throw new AppExcpetion(ErrorCode.RESPONSE_DATA_BUILD_ERROR);
+                throw new AppException(ErrorCode.RESPONSE_DATA_BUILD_ERROR);
             }
         }
         return result;
@@ -409,13 +409,13 @@ public class GfsDataServiceImpl implements IDataService {
         long milli = (long) lastGridDataSetMeta.getAttributes().get(AttributionEnum.REFERENCE_TIME.getName());
         OffsetDateTime refTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(milli), ZoneOffset.ofHours(0));
         if (targetTime.isBefore(refTime)) {
-            throw new AppExcpetion(ErrorCode.QUERY_TIME_ERROR);
+            throw new AppException(ErrorCode.QUERY_TIME_ERROR);
         }
 
         List<String> forecastHours = lastGridDataSetMeta.getForecastHours();
         String targetHour = String.valueOf(getForecastHourFromTargetTime(targetTime, refTime));
         if (!forecastHours.contains(targetHour)) {
-            throw new AppExcpetion(ErrorCode.QUERY_TIME_ERROR);
+            throw new AppException(ErrorCode.QUERY_TIME_ERROR);
         }
         int iTime = forecastHours.indexOf(targetHour);
         return iTime;
@@ -426,7 +426,7 @@ public class GfsDataServiceImpl implements IDataService {
         OffsetDateTime refTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(milli), ZoneOffset.ofHours(0));
         OffsetDateTime currentTime = DateTimeUtils.getUTCDateTime(OffsetDateTime.now());
         if (currentTime.isBefore(refTime)) {
-            throw new AppExcpetion(ErrorCode.QUERY_TIME_ERROR);
+            throw new AppException(ErrorCode.QUERY_TIME_ERROR);
         }
         int startHour = getForecastHourFromTargetTime(currentTime, refTime);
         List<String> forecastHours = lastGridDataSetMeta.getForecastHours();
@@ -446,7 +446,7 @@ public class GfsDataServiceImpl implements IDataService {
             }
         }
         if (CollectionUtils.isEmpty(iTimeList) || CollectionUtils.isEmpty(timeList)) {
-            throw new AppExcpetion(ErrorCode.QUERY_TIME_ERROR);
+            throw new AppException(ErrorCode.QUERY_TIME_ERROR);
         }
         Map<String, List> map = new HashMap<>(2);
         map.put("iTimeList", iTimeList);
@@ -457,16 +457,16 @@ public class GfsDataServiceImpl implements IDataService {
     private int getLongitudeIndex(double lon) {
         double[] lonList = tableConfig.getLonList();
         if (lonList.length == 0) {
-            throw new AppExcpetion(ErrorCode.LONGITUDE_INDEX_ERROR, "经度列表为空, 无法查找索引");
+            throw new AppException(ErrorCode.LONGITUDE_INDEX_ERROR, "经度列表为空, 无法查找索引");
         }
         double minLon = lonList[0];
         double maxLon = lonList[lonList.length - 1];
         if (minLon > lon || lon > maxLon) {
-            throw new AppExcpetion(ErrorCode.LONGITUDE_INDEX_ERROR, "经度不在有效范围内: " + minLon + " ~ " + maxLon);
+            throw new AppException(ErrorCode.LONGITUDE_INDEX_ERROR, "经度不在有效范围内: " + minLon + " ~ " + maxLon);
         }
         int nearestIndex = NdArrayUtils.findNearestIndex(lonList, lon);
         if (nearestIndex == -1) {
-            throw new AppExcpetion(ErrorCode.LONGITUDE_INDEX_ERROR, "找不到" + lon + "的经度索引");
+            throw new AppException(ErrorCode.LONGITUDE_INDEX_ERROR, "找不到" + lon + "的经度索引");
         }
         return nearestIndex;
     }
@@ -474,17 +474,17 @@ public class GfsDataServiceImpl implements IDataService {
     private int getLatitudeIndex(double lat) {
         double[] latList = tableConfig.getLatList();
         if (latList.length == 0) {
-            throw new AppExcpetion(ErrorCode.LATITUDE_INDEX_ERROR, "纬度列表为空, 无法查找索引");
+            throw new AppException(ErrorCode.LATITUDE_INDEX_ERROR, "纬度列表为空, 无法查找索引");
         }
         double minLat = latList[0];
         double maxLat = latList[latList.length - 1];
 
         if (minLat > lat || lat > maxLat) {
-            throw new AppExcpetion(ErrorCode.LATITUDE_INDEX_ERROR, "纬度不在有效范围内: " + minLat + " ~ " + maxLat);
+            throw new AppException(ErrorCode.LATITUDE_INDEX_ERROR, "纬度不在有效范围内: " + minLat + " ~ " + maxLat);
         }
         int nearestIndex = NdArrayUtils.findNearestIndex(latList, lat);
         if (nearestIndex == -1) {
-            throw new AppExcpetion(ErrorCode.LATITUDE_INDEX_ERROR, "找不到" + lat + "的纬度索引");
+            throw new AppException(ErrorCode.LATITUDE_INDEX_ERROR, "找不到" + lat + "的纬度索引");
         }
         return nearestIndex;
     }
@@ -492,11 +492,11 @@ public class GfsDataServiceImpl implements IDataService {
     private int getPressureIndex(int pressureLevel) {
         List<Integer> levList = Arrays.stream(tableConfig.getPressureList()).boxed().collect(Collectors.toList());
         if (CollectionUtils.isEmpty(levList)) {
-            throw new AppExcpetion(ErrorCode.LEVEL_INDEX_ERROR, "气压列表为空, 无法查找索引");
+            throw new AppException(ErrorCode.LEVEL_INDEX_ERROR, "气压列表为空, 无法查找索引");
         }
         int index = levList.indexOf(pressureLevel);
         if (index == -1) {
-            throw new AppExcpetion(ErrorCode.LATITUDE_INDEX_ERROR, "找不到" + pressureLevel + "的气压高度索引");
+            throw new AppException(ErrorCode.LATITUDE_INDEX_ERROR, "找不到" + pressureLevel + "的气压高度索引");
         }
         return index;
     }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/CaiYunServiceImpl.java b/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/CaiYunServiceImpl.java
index da00d7a..ce73e73 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/CaiYunServiceImpl.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/CaiYunServiceImpl.java
@@ -3,7 +3,7 @@ package com.htfp.weather.web.service.surfaceapi;
 import com.htfp.weather.info.CaiYunInfo;
 import com.htfp.weather.utils.DateTimeUtils;
 import com.htfp.weather.utils.MeteoUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.caiyun.*;
 import com.htfp.weather.web.pojo.caiyun.CaiYunNowResponse.NowResult.RealTime;
@@ -42,10 +42,10 @@ public class CaiYunServiceImpl implements ISurfaceDataService {
                 return response;
             } else if (response == null) {
                 log.error("[彩云天气] 请求失败");
-                throw new AppExcpetion(ErrorCode.CAI_YUN_REQUEST_ERROR);
+                throw new AppException(ErrorCode.CAI_YUN_REQUEST_ERROR);
             } else {
                 log.error("[彩云天气] {}: {}", ErrorCode.CAI_YUN_REQUEST_ERROR.getMsg(), response);
-                throw new AppExcpetion(ErrorCode.CAI_YUN_REQUEST_ERROR);
+                throw new AppException(ErrorCode.CAI_YUN_REQUEST_ERROR);
             }
         } catch (Exception e) {
             log.error("[彩云天气] 请求结果处理错误, {}", e.getMessage());
@@ -109,7 +109,7 @@ public class CaiYunServiceImpl implements ISurfaceDataService {
         CaiYunWarningResponse response = caiYunRequest(url, params, CaiYunWarningResponse.class);
         CaiYunWarningResponse.AlertResult.Alert alert = response.getResult().getAlert();
         if (alert == null) {
-            throw new AppExcpetion(ErrorCode.CAI_YUN_REQUEST_ERROR, ":无可用预警数据");
+            throw new AppException(ErrorCode.CAI_YUN_REQUEST_ERROR, ":无可用预警数据");
         }
         return alert.getContent();
     }
@@ -133,7 +133,7 @@ public class CaiYunServiceImpl implements ISurfaceDataService {
             }
             return nowWeatherStatus;
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.CAI_YUN_DATA_PARSE_ERROR);
+            throw new AppException(ErrorCode.CAI_YUN_DATA_PARSE_ERROR);
         }
     }
 
@@ -151,7 +151,7 @@ public class CaiYunServiceImpl implements ISurfaceDataService {
             }
             return timeSeriesDataset;
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.CAI_YUN_DATA_PARSE_ERROR, e.getMessage());
+            throw new AppException(ErrorCode.CAI_YUN_DATA_PARSE_ERROR, e.getMessage());
         }
     }
 
@@ -170,7 +170,7 @@ public class CaiYunServiceImpl implements ISurfaceDataService {
             }
             return surfaceWeatherWarnings;
         } catch (Exception e) {
-            throw new AppExcpetion(ErrorCode.CAI_YUN_DATA_PARSE_ERROR);
+            throw new AppException(ErrorCode.CAI_YUN_DATA_PARSE_ERROR);
         }
     }
 }
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/HeFengServiceImpl.java b/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/HeFengServiceImpl.java
index df44a76..c92c744 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/HeFengServiceImpl.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/surfaceapi/HeFengServiceImpl.java
@@ -2,7 +2,7 @@ package com.htfp.weather.web.service.surfaceapi;
 
 import com.htfp.weather.utils.DateTimeUtils;
 import com.htfp.weather.utils.MeteoUtils;
-import com.htfp.weather.web.exception.AppExcpetion;
+import com.htfp.weather.web.exception.AppException;
 import com.htfp.weather.web.exception.ErrorCode;
 import com.htfp.weather.web.pojo.response.SurfaceWeatherWarning;
 import com.htfp.weather.web.pojo.response.TimeSeriesDataset;
@@ -58,13 +58,13 @@ public class HeFengServiceImpl implements ISurfaceDataService {
                 return response;
             } else if (response == null) {
                 log.error("[和风天气] 请求失败");
-                throw new AppExcpetion(ErrorCode.HE_FENG_REQUEST_ERROR);
+                throw new AppException(ErrorCode.HE_FENG_REQUEST_ERROR);
             } else if (STATUS_NO_DATA.equals(response.getCode())) {
                 log.error("[和风天气] {}: {}", ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA.getMsg(), response);
-                throw new AppExcpetion(ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA);
+                throw new AppException(ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA);
             } else {
                 log.error("[和风天气] {}: {}", ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA.getMsg(), response);
-                throw new AppExcpetion(ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA);
+                throw new AppException(ErrorCode.HE_FENG_THIS_AREA_HAVE_NO_DATA);
             }
         } catch (Exception e) {
             log.error("[和风天气] 请求结果处理错误, {}", e.getMessage());