From 2ec081e80f79904724afc07c90f18fc788cd23f5 Mon Sep 17 00:00:00 2001 From: shiyi <shi_yee@outlook.com> Date: Mon, 1 Jul 2024 17:55:23 +0800 Subject: [PATCH] =?UTF-8?q?package=E9=83=A8=E5=88=86=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E7=BB=84=E7=BB=87=EF=BC=9B=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/htfp/weather/config/Config.java | 18 ---- .../weather/download/BaseDataDownloader.java | 13 +-- .../download/{ => gfs}/GfsDataConfig.java | 4 +- .../gfs}/GfsDownloadVariableEnum.java | 2 +- .../download/{ => gfs}/GfsDownloader.java | 27 ++---- .../{info => download/gfs}/GfsLevelsEnum.java | 3 +- .../gfs}/GfsVariableHeightEnum.java | 4 +- .../gfs}/GfsVariableIsobaricEnum.java | 4 +- .../weather/griddata/common/TableConfig.java | 2 +- .../griddata/common/TableConfigStatic.java | 2 +- .../{utils => common}/ValueRange.java | 4 +- .../griddata/operation/GfsDataFetcher.java | 18 +++- .../griddata/operation/GfsDataImport.java | 51 ++++++---- .../griddata/operation/IDataFetch.java | 9 -- .../weather/schedule/GridDataProcessor.java | 12 +-- .../com/htfp/weather/utils/DateTimeUtils.java | 2 +- .../htfp/weather/utils/HttpClientUtils.java | 5 +- .../web/controller/ConfigController.java | 4 +- .../controller/SurfaceWeatherController.java | 10 +- .../controller/UpperWeatherController.java | 39 +++++--- .../web/pojo/request/GfsConfigUpdate.java | 2 +- .../web/pojo/request/PlaneRequest.java | 17 ++-- .../web/pojo/request/ProfileRequest.java | 1 - .../web/pojo/response/ProfileDataset.java | 42 ++++++++ .../web/service/GfsDataServiceImpl.java | 95 +++++++++++++------ .../service/surfaceapi/CaiYunServiceImpl.java | 6 +- .../service/surfaceapi/HeFengServiceImpl.java | 15 +-- .../weather/download/GfsDataConfigTest.java | 3 +- .../weather/download/GfsDownloaderTest.java | 4 +- .../operation/GfsDataFetcherTest.java | 3 +- .../weather/griddata/utils/GfsUtilsTest.java | 30 ------ 31 files changed, 249 insertions(+), 202 deletions(-) delete mode 100644 weather-service/src/main/java/com/htfp/weather/config/Config.java rename weather-service/src/main/java/com/htfp/weather/download/{ => gfs}/GfsDataConfig.java (97%) rename weather-service/src/main/java/com/htfp/weather/{info => download/gfs}/GfsDownloadVariableEnum.java (96%) rename weather-service/src/main/java/com/htfp/weather/download/{ => gfs}/GfsDownloader.java (93%) rename weather-service/src/main/java/com/htfp/weather/{info => download/gfs}/GfsLevelsEnum.java (95%) rename weather-service/src/main/java/com/htfp/weather/{griddata/common => download/gfs}/GfsVariableHeightEnum.java (94%) rename weather-service/src/main/java/com/htfp/weather/{griddata/common => download/gfs}/GfsVariableIsobaricEnum.java (94%) rename weather-service/src/main/java/com/htfp/weather/griddata/{utils => common}/ValueRange.java (85%) delete mode 100644 weather-service/src/main/java/com/htfp/weather/griddata/operation/IDataFetch.java create mode 100644 weather-service/src/main/java/com/htfp/weather/web/pojo/response/ProfileDataset.java delete mode 100644 weather-service/src/test/java/com/htfp/weather/griddata/utils/GfsUtilsTest.java diff --git a/weather-service/src/main/java/com/htfp/weather/config/Config.java b/weather-service/src/main/java/com/htfp/weather/config/Config.java deleted file mode 100644 index 33979cc..0000000 --- a/weather-service/src/main/java/com/htfp/weather/config/Config.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.htfp.weather.config; - -import com.htfp.weather.griddata.common.TableConfig; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * @Author : shiyi - * @Date : 2024/1/22 19:02 - * @Description : - */ -@Component("config") -public class Config { - @Resource - TableConfig tableConfig; - -} diff --git a/weather-service/src/main/java/com/htfp/weather/download/BaseDataDownloader.java b/weather-service/src/main/java/com/htfp/weather/download/BaseDataDownloader.java index 73fb052..633eef9 100644 --- a/weather-service/src/main/java/com/htfp/weather/download/BaseDataDownloader.java +++ b/weather-service/src/main/java/com/htfp/weather/download/BaseDataDownloader.java @@ -8,8 +8,9 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.util.List; -/** - * @author shiyi +/** @Author : shiyi + * @Date : 2024/2/28 13:53 + * @Description : GFS数据下载类 */ @Data @ToString @@ -36,16 +37,10 @@ public abstract class BaseDataDownloader { /** * 下载所有目标文件 - * - * @param filesInfo + * @param fileInfoList * @return */ public abstract List<FileInfo> downloadAll(List<FileInfo> fileInfoList); - - public BaseDataDownloader() { - - } - } diff --git a/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDataConfig.java similarity index 97% rename from weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDataConfig.java index 5b9a964..2d21a20 100644 --- a/weather-service/src/main/java/com/htfp/weather/download/GfsDataConfig.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDataConfig.java @@ -1,8 +1,6 @@ -package com.htfp.weather.download; +package com.htfp.weather.download.gfs; 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.AppException; import com.htfp.weather.web.exception.ErrorCode; diff --git a/weather-service/src/main/java/com/htfp/weather/info/GfsDownloadVariableEnum.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloadVariableEnum.java similarity index 96% rename from weather-service/src/main/java/com/htfp/weather/info/GfsDownloadVariableEnum.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloadVariableEnum.java index 954d5a2..b546ba6 100644 --- a/weather-service/src/main/java/com/htfp/weather/info/GfsDownloadVariableEnum.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloadVariableEnum.java @@ -1,4 +1,4 @@ -package com.htfp.weather.info; +package com.htfp.weather.download.gfs; /** * @Author : shiyi diff --git a/weather-service/src/main/java/com/htfp/weather/download/GfsDownloader.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloader.java similarity index 93% rename from weather-service/src/main/java/com/htfp/weather/download/GfsDownloader.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloader.java index 1304f76..7eb02a0 100644 --- a/weather-service/src/main/java/com/htfp/weather/download/GfsDownloader.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsDownloader.java @@ -1,10 +1,11 @@ -package com.htfp.weather.download; +package com.htfp.weather.download.gfs; +import com.htfp.weather.download.BaseDataDownloader; +import com.htfp.weather.download.FileInfo; import com.htfp.weather.info.Constant; import com.htfp.weather.utils.DateTimeUtils; import com.htfp.weather.utils.HttpClientUtils; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Component; @@ -13,12 +14,7 @@ import ucar.nc2.NetcdfFiles; import javax.annotation.Resource; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; -import java.net.ConnectException; -import java.net.URL; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; @@ -30,6 +26,7 @@ import java.util.concurrent.Future; /** * @author shiyi + * @ */ @Slf4j @Component("gfsDownloader") @@ -42,7 +39,6 @@ public class GfsDownloader extends BaseDataDownloader { private OffsetDateTime realUpdateDateTime; public GfsDownloader(GfsDataConfig gfsDataConfig) { - super(); this.gfsDataConfig = gfsDataConfig; } @@ -58,8 +54,8 @@ public class GfsDownloader extends BaseDataDownloader { realUpdateDateTime = getAvailableUpdateDateTime(utcStartTime); this.setRefTime(realUpdateDateTime); this.setRefTimeStr(realUpdateDateTime.format(DateTimeFormatter.ofPattern(Constant.UTC_TIME_STRING))); - // 起报点和实际请求时间的差异 + // 起报点和实际请求时间的差异 this.hourDiff = (int) Duration.between(realUpdateDateTime, utcStartTime).toHours(); log.info("[GFS Download] 起始为当前本地时间:{}", this.getStartTime()); log.info("[GFS Download] GFS最近更新时间UTC:{},本地时间: {}", realUpdateDateTime, DateTimeUtils.getLocalZoneDateTime(realUpdateDateTime)); @@ -69,24 +65,20 @@ public class GfsDownloader extends BaseDataDownloader { public FileInfo download(FileInfo fileInfo) { return download0(fileInfo, 2); } - private FileInfo download0(FileInfo fileInfo, int retryNum) { + private FileInfo download0(FileInfo fileInfo, int retryNum) { String url = fileInfo.getUrl(); File destDir = new File(fileInfo.getSavePath()); File fileOut = new File(destDir, fileInfo.getFileName()); log.info("[GFS Download] 文件下载中,保存至 {}", fileOut); try { - // TODO 2024/5/24: 增加重试机制 - // if (fileInfo.getForecastHour() == 12 || fileInfo.getForecastHour() == 18 || fileInfo.getForecastHour() == 24) { - // throw new RuntimeException(); - // } - // FileUtils.copyURLToFile(new URL(url), fileOut, 30000, 30000); - // FIXME 2024/6/8: 如果连接是https,jar包下载会报错 javax.net.ssl.SSLException: Received fatal alert: internal_error + // DONE: 改用okhttp FIXME 2024/6/8: 如果连接是https,jar包启动下载会报错 javax.net.ssl.SSLException: Received fatal alert: internal_error HttpClientUtils.downloadFileByUrl(url, fileOut.getPath()); log.info("[GFS Download] 文件下载成功: {}", fileOut); fileInfo.setDownloadSuccess(fileValid(fileOut.getAbsolutePath())); } catch (Exception e) { + // DONE 2024/5/24: 文件服务器在外网不稳定,增加重试机制 fileInfo.setDownloadSuccess(false); if (retryNum > 0) { log.error("[GFS Download] 文件下载失败,重试中: {}", fileOut); @@ -99,6 +91,7 @@ public class GfsDownloader extends BaseDataDownloader { return fileInfo; } + /** 简单校验验证文件完整性,并生成索引文件*/ private boolean fileValid(String file) { try (NetcdfFile ncFile = NetcdfFiles.open(file)) { ncFile.getLocation(); @@ -274,7 +267,7 @@ public class GfsDownloader extends BaseDataDownloader { for (String variable : variables) { stringJoiner.add(String.format("var_%s=on", variable)); } - stringJoiner.add("lev_surface=on"); // gust需要 + stringJoiner.add("lev_surface=on"); // gust, prate需要 return stringJoiner.toString(); } diff --git a/weather-service/src/main/java/com/htfp/weather/info/GfsLevelsEnum.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsLevelsEnum.java similarity index 95% rename from weather-service/src/main/java/com/htfp/weather/info/GfsLevelsEnum.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsLevelsEnum.java index bdb7243..66b4c6e 100644 --- a/weather-service/src/main/java/com/htfp/weather/info/GfsLevelsEnum.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsLevelsEnum.java @@ -1,4 +1,4 @@ -package com.htfp.weather.info; +package com.htfp.weather.download.gfs; /** * @Author : shiyi @@ -8,6 +8,7 @@ package com.htfp.weather.info; public enum GfsLevelsEnum { // SURFACE(9999, "地面"), + UPPER(0, "高空"), PRES_1000hPa(1000, "1000 hPa"), PRES_975hPa(975, "975 hPa"), PRES_950hPa(950, "950 hPa"), diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableHeightEnum.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableHeightEnum.java similarity index 94% rename from weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableHeightEnum.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableHeightEnum.java index d769374..75feacc 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableHeightEnum.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableHeightEnum.java @@ -1,4 +1,4 @@ -package com.htfp.weather.griddata.common; +package com.htfp.weather.download.gfs; import java.util.ArrayList; import java.util.List; @@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * @Author : shiyi * @Date : 2024/1/15 14:54 - * @Description : 文件变量名和表中变量名的映射 + * @Description : 文件高度坐标变量名和表中变量名的映射 */ public enum GfsVariableHeightEnum { // diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableIsobaricEnum.java b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableIsobaricEnum.java similarity index 94% rename from weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableIsobaricEnum.java rename to weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableIsobaricEnum.java index defb295..6051dec 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/common/GfsVariableIsobaricEnum.java +++ b/weather-service/src/main/java/com/htfp/weather/download/gfs/GfsVariableIsobaricEnum.java @@ -1,4 +1,4 @@ -package com.htfp.weather.griddata.common; +package com.htfp.weather.download.gfs; import java.util.ArrayList; import java.util.List; @@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * @Author : shiyi * @Date : 2024/1/15 14:54 - * @Description : 文件变量名和表中变量名的映射 + * @Description : 文件气压坐标变量名和表中变量名的映射 */ public enum GfsVariableIsobaricEnum { // diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfig.java b/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfig.java index 4f9e376..e5e7991 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfig.java +++ b/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfig.java @@ -2,7 +2,7 @@ package com.htfp.weather.griddata.common; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.htfp.weather.download.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDataConfig; import com.htfp.weather.utils.JSONUtils; import lombok.Data; import lombok.extern.slf4j.Slf4j; diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfigStatic.java b/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfigStatic.java index 607e605..bcf7b63 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfigStatic.java +++ b/weather-service/src/main/java/com/htfp/weather/griddata/common/TableConfigStatic.java @@ -1,7 +1,7 @@ package com.htfp.weather.griddata.common; import com.google.gson.Gson; -import com.htfp.weather.download.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDataConfig; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/utils/ValueRange.java b/weather-service/src/main/java/com/htfp/weather/griddata/common/ValueRange.java similarity index 85% rename from weather-service/src/main/java/com/htfp/weather/griddata/utils/ValueRange.java rename to weather-service/src/main/java/com/htfp/weather/griddata/common/ValueRange.java index aa8ae90..b0c05bb 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/utils/ValueRange.java +++ b/weather-service/src/main/java/com/htfp/weather/griddata/common/ValueRange.java @@ -1,9 +1,11 @@ -package com.htfp.weather.griddata.utils; +package com.htfp.weather.griddata.common; import lombok.Getter; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * @Author : shiyi diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataFetcher.java b/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataFetcher.java index c9a30b1..9c4a5f7 100644 --- a/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataFetcher.java +++ b/weather-service/src/main/java/com/htfp/weather/griddata/operation/GfsDataFetcher.java @@ -7,8 +7,8 @@ import com.aliyun.tablestore.grid.model.GridDataSet; import com.aliyun.tablestore.grid.model.GridDataSetMeta; import com.aliyun.tablestore.grid.model.grid.Range; import com.htfp.weather.griddata.common.TableConfig; -import com.htfp.weather.griddata.utils.ValueRange; -import com.htfp.weather.info.GfsLevelsEnum; +import com.htfp.weather.griddata.common.ValueRange; +import com.htfp.weather.download.gfs.GfsLevelsEnum; import com.htfp.weather.utils.NdArrayUtils; import com.htfp.weather.web.exception.AppException; import com.htfp.weather.web.exception.ErrorCode; @@ -154,7 +154,19 @@ public class GfsDataFetcher extends BaseTableOperation { Array array = gridDataSet.getVariable(variableName).toArray(); return array; } - + public GridDataSet getProfileByPressure(List<String> variableNameList, OffsetDateTime targetTime, double latitude, double longitude) throws Exception { + lastGridDataSetMeta = getLastGridDataSetMeta(); + GridDataFetcher fetcher = tableStoreGrid.getDataFetcher(lastGridDataSetMeta); + int iTime = getTargetTimeIndex(targetTime); + int iLat= getLatitudeIndex(latitude); + int iLon = getLongitudeIndex(longitude); + int[] origin = new int[]{iTime, 0, iLat, iLon}; + int[] shape = new int[]{1,tableConfig.levSize, 1, 1}; + // TODO 2024/6/17: + fetcher.setVariablesToGet(variableNameList); + fetcher.setOriginShape(origin, shape); + return fetcher.fetch(); + } /** * 获取指定变量在某经纬高处的预报序列 * @param dataSetId 数据集ID 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 4ecfd8a..a640cdc 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 @@ -5,8 +5,9 @@ import com.aliyun.tablestore.grid.model.GridDataSetMeta; import com.aliyun.tablestore.grid.model.StoreOptions; import com.aliyun.tablestore.grid.model.grid.Grid2D; -import com.htfp.weather.griddata.common.GfsVariableHeightEnum; -import com.htfp.weather.griddata.common.GfsVariableIsobaricEnum; +import com.htfp.weather.download.FileInfo; +import com.htfp.weather.download.gfs.GfsVariableHeightEnum; +import com.htfp.weather.download.gfs.GfsVariableIsobaricEnum; import com.htfp.weather.griddata.common.TableConfig; import com.htfp.weather.info.Constant; import com.htfp.weather.utils.MeteoUtils; @@ -32,6 +33,8 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; /** * @author shi_y @@ -85,57 +88,64 @@ public class GfsDataImport extends BaseTableOperation { * @throws Exception */ public GridDataSetMeta updateMeta(GridDataSetMeta meta) throws Exception { - meta.addAttribute("status", "DONE"); tableStoreGrid.updateDataSetMeta(meta); return meta; } public GridDataSetMeta putMeta(GridDataSetMeta meta) throws Exception { - meta.addAttribute("status", "DONE"); tableStoreGrid.putDataSetMeta(meta); return meta; } + /** 导入指定起报时间的所有文件*/ public List<ImportResult> importData(OffsetDateTime refTime) throws Exception { + importing = true; long start = System.currentTimeMillis(); List<String> fileList = getFiles(refTime); if (CollectionUtils.isEmpty(fileList)) { throw new AppException(ErrorCode.NO_NC_OR_GRIB_FILES); } log.info("[tablestore] 数据导入开始, refTime = {}...", refTime); + // datasetId和起报时间绑定 String dataSetId = refTime.format(DateTimeFormatter.ofPattern(Constant.DATA_SET_ID_FORMAT_STRING)); List<String> fileVariables = getFileVariables(tableConfig.variableList); int[] shape = new int[]{tableConfig.timeSizeMax, tableConfig.levSize, tableConfig.latSize, tableConfig.lonSize}; GridDataSetMeta meta = initMeta(dataSetId, tableConfig.dataType, fileVariables, shape); - List<String> forecastHours = new ArrayList<>(); // 记录到数据库属性中 - - // done 2024/5/13: 待优化,用于数据库的索引,必须连续,因此必须保证前一个时刻成功导入后才能导入下一个时刻,数据量大的时候导入时间较长 - // done 2024/5/13: 优化方案,使用多线程,并使用Future来获取结果,但是必须保证每个时刻都成功导入 + List<String> forecastHours = new ArrayList<>(); // 所有有效预报时效坐标记录到数据库属性中 + // todo 2024/5/13: 待优化,用于数据库的索引,必须连续,因此必须保证前一个时刻成功导入后才能导入下一个时刻,数据量大的时候导入时间较长 List<ImportResult> finishedList; - try { + // List<Future<ImportResult>> futures = new ArrayList<>(); finishedList = new ArrayList<>(); for (int i = 0; i < fileList.size(); i++) { - // for(int i = 0; i < 200; i++) { String file = fileList.get(i); int iTime = i; int forecastHour = getForecastHourFromFilename(file); - // futures.add(executorService.submit(() -> importFromNcFile(meta, file, iTime))); + // 2024/5/13:使用多线程,并使用Future来获取结果,但是实际瓶颈可能是网络带宽而非计算 + // futures.add(executorService.submit(() -> importFromNcFile(meta, file, iTime,forecastHour))); ImportResult importResult = importFromNcFile(meta, file, iTime, forecastHour); finishedList.add(importResult); - // ImportResult importResult = importFromNcFile(meta, file, 0, forecastHour); if (importResult.isSuccess()) { forecastHours.add(String.valueOf(importResult.getForecastHour())); } } - } finally { - importing = false; - } // for (Future<ImportResult> future : futures) { // ImportResult importResult = future.get(); - // forecastHours.add(String.valueOf(importResult.getForcastHour())); + // finishedList.add(importResult); + // forecastHours.add(String.valueOf(importResult.getForecastHour())); + // if (importResult.isSuccess()) { + // forecastHours.add(String.valueOf(importResult.getForecastHour())); + // } // } + + List<ImportResult> failedList = finishedList.stream().filter(result -> !result.isSuccess()).collect(Collectors.toList()); + if (!failedList.isEmpty()) { + log.warn("存在气象数据导入数据库失败,失败文件列表: {} ", failedList); + meta.addAttribute("status", "WRONG"); + } else { + meta.addAttribute("status", "DONE"); + } long end = System.currentTimeMillis(); log.info("[tablestore] 数据导入完成, 耗时: {} s, forecastHours: {}", (end - start)/1000., forecastHours); meta.setForecastHours(forecastHours); @@ -143,15 +153,16 @@ public class GfsDataImport extends BaseTableOperation { putMeta(meta); gfsDataFetcher.lastGridDataSetMeta = meta; log.info("[tablestore]: 更新最新的数据元信息: {}", meta); + importing = false; return finishedList; } /** - * read data from netcdf file and write data to table store. - * + * 读取grib/nc文件,并进行相关计算,最后导入tablestore数据库 * @param meta 数据元信息 * @param file netcdf文件路径 * @param iTime 文件序号 + * @param forecastHour 预报时效(相对于起报时间的小时数) */ public ImportResult importFromNcFile(GridDataSetMeta meta, String file, int iTime, int forecastHour) { try (NetcdfFile ncFile = NetcdfFiles.open(file)) { @@ -191,7 +202,6 @@ public class GfsDataImport extends BaseTableOperation { new int[]{0, 0}, new int[]{xsize, ysize}); writer.writeGrid2D(variableName, iTime, 0, grid2D); } - } else { log.warn("[tablestore] 数据文件 {} 中没有变量 {}", ncFile.getLocation(), variableName); } @@ -218,8 +228,9 @@ public class GfsDataImport extends BaseTableOperation { } } + /** 计算风速风向,包括地面坐标和气压坐标,并导入数据库*/ private void importWind(GridDataWriter writer, GridDataSetMeta meta, NetcdfFile ncFile, int iTime) throws Exception { - // TODO 2024/5/8: 风速风向需要保存到文件中 + // TODO 2024/5/8: 风速风向最好单独保存为一个文件,如果后续需要二维可视化,可以直接本地读取出图,减少网络请求 for (String suffix : new String[]{"_isobaric", "_height_above_ground"}) { Variable uwnd = ncFile.findVariable("u-component_of_wind" + suffix); Variable vwnd = ncFile.findVariable("v-component_of_wind" + suffix); diff --git a/weather-service/src/main/java/com/htfp/weather/griddata/operation/IDataFetch.java b/weather-service/src/main/java/com/htfp/weather/griddata/operation/IDataFetch.java deleted file mode 100644 index 80b317a..0000000 --- a/weather-service/src/main/java/com/htfp/weather/griddata/operation/IDataFetch.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.htfp.weather.griddata.operation; - -/** - * @Author : shiyi - * @Date : 2024/2/2 13:47 - * @Description : 获取数据 - */ -public interface IDataFetch { -} 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 e05e5f2..fd9994f 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 @@ -1,9 +1,8 @@ package com.htfp.weather.schedule; -import com.aliyun.tablestore.grid.model.GridDataSetMeta; import com.htfp.weather.download.FileInfo; -import com.htfp.weather.download.GfsDataConfig; -import com.htfp.weather.download.GfsDownloader; +import com.htfp.weather.download.gfs.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDownloader; import com.htfp.weather.griddata.operation.GfsDataFetcher; import com.htfp.weather.griddata.operation.GfsDataImport; import com.htfp.weather.griddata.operation.GfsDataImport.ImportResult; @@ -23,7 +22,6 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -43,8 +41,6 @@ public class GridDataProcessor { @Resource GfsDownloader gfsDownloader; @Resource - GfsDataFetcher gfsDataFetcher; - @Resource GfsDataConfig gfsDataConfig; @Resource ErrorReportService errorReportService; @@ -54,8 +50,10 @@ public class GridDataProcessor { private final ExecutorService executorService = Executors.newFixedThreadPool(3); boolean test = false; + + /**每日北京时0,8,12,18点执行*/ @Scheduled(cron = "0 0 0,8,12,18 * * ?") - public void dailyDataProcess() throws Exception { + public void dailyDataProcess() { if (download()) { importToTableStore(); } diff --git a/weather-service/src/main/java/com/htfp/weather/utils/DateTimeUtils.java b/weather-service/src/main/java/com/htfp/weather/utils/DateTimeUtils.java index da11e0a..7161c0f 100644 --- a/weather-service/src/main/java/com/htfp/weather/utils/DateTimeUtils.java +++ b/weather-service/src/main/java/com/htfp/weather/utils/DateTimeUtils.java @@ -9,7 +9,7 @@ import java.time.format.DateTimeFormatter; * @Description : 日期时间工具类 */ public class DateTimeUtils { - public static final String DEFAULT_PATTERN = "yyyy-MM-dd'T'HH:mmxxx"; + public static final String DEFAULT_PATTERN = "yyyy-MM-dd'T'HH:mm:ssxxx"; public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_PATTERN); /** * 将某时区的时间字符串更改为其他时区的时间字符串, diff --git a/weather-service/src/main/java/com/htfp/weather/utils/HttpClientUtils.java b/weather-service/src/main/java/com/htfp/weather/utils/HttpClientUtils.java index cc84aaf..ca293d5 100644 --- a/weather-service/src/main/java/com/htfp/weather/utils/HttpClientUtils.java +++ b/weather-service/src/main/java/com/htfp/weather/utils/HttpClientUtils.java @@ -89,7 +89,7 @@ public class HttpClientUtils { } - public static boolean downloadFileByUrl(String sourceUrl, String localPath) throws IOException { + public static boolean downloadFileByUrl(String sourceUrl, String localPath) { File file = new File(localPath); Request request = new Request.Builder() .url(sourceUrl) @@ -102,8 +102,9 @@ public class HttpClientUtils { } else { return false; } + } catch (IOException e) { + return false; } - return true; } 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 6941629..8b46988 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 @@ -1,8 +1,8 @@ package com.htfp.weather.web.controller; import com.htfp.weather.download.FileInfo; -import com.htfp.weather.download.GfsDataConfig; -import com.htfp.weather.download.GfsDownloader; +import com.htfp.weather.download.gfs.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDownloader; import com.htfp.weather.griddata.common.TableConfig; import com.htfp.weather.griddata.operation.GfsDataImport; import com.htfp.weather.griddata.operation.GfsDataImport.ImportResult; diff --git a/weather-service/src/main/java/com/htfp/weather/web/controller/SurfaceWeatherController.java b/weather-service/src/main/java/com/htfp/weather/web/controller/SurfaceWeatherController.java index 8f637ea..3ff8705 100644 --- a/weather-service/src/main/java/com/htfp/weather/web/controller/SurfaceWeatherController.java +++ b/weather-service/src/main/java/com/htfp/weather/web/controller/SurfaceWeatherController.java @@ -29,7 +29,7 @@ public class SurfaceWeatherController { @Resource(name = "hefeng") ISurfaceDataService surfaceDataService; - @PostMapping("/now") + @PostMapping("/querySurfaceNowWeather") public Result queryNowWeather(@Validated @RequestBody Position2D position2D) throws Exception { double lat = position2D.getLatitude(); double lon = position2D.getLongitude(); @@ -41,8 +41,8 @@ public class SurfaceWeatherController { return Result.success(nowWeatherStatus); } - @PostMapping("/forecast") - public Result querySurfaceForecastWeather(@Validated @RequestBody Position2D position2D) throws Exception { + @PostMapping("/querySurfaceForecast") + public Result querySurfaceForecast(@Validated @RequestBody Position2D position2D) throws Exception { double lat = position2D.getLatitude(); double lon = position2D.getLongitude(); log.info("[data-server] 地面24小时预报结果查询 start: param={}", position2D); @@ -53,8 +53,8 @@ public class SurfaceWeatherController { return Result.success(forecastSeries); } - @PostMapping ("/warning") - public Result warning(@Validated @RequestBody Position2D position2D) throws Exception { + @PostMapping ("/queryWeatherWarning") + public Result queryWeatherWarning(@Validated @RequestBody Position2D position2D) throws Exception { double lat = position2D.getLatitude(); double lon = position2D.getLongitude(); log.info("[data-server] 地面气象预警信息查询 start: param={}", position2D); 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 a951c15..beecc36 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,6 +1,5 @@ package com.htfp.weather.web.controller; -import com.htfp.weather.info.Constant; import com.htfp.weather.utils.DateTimeUtils; import com.htfp.weather.web.exception.AppException; import com.htfp.weather.web.exception.ErrorCode; @@ -19,7 +18,7 @@ import java.util.List; /** * @Author : shiyi * @Date : 2024/5/8 15:15 - * @Description : + * @Description : 高空天气查询接口 */ @CrossOrigin @RestController @Slf4j @@ -61,8 +60,8 @@ public class UpperWeatherController { return Result.success(nowWeatherByMultiPoint); } - @PostMapping("/queryForecastTimeSeries24Hour") - public Result queryForecastTimeSeries(@Validated @RequestBody Position3D position3D) { + @PostMapping("/queryUpperForecast") + public Result queryUpperForecast(@Validated @RequestBody Position3D position3D) { double latitude = position3D.getLatitude(); double longitude = position3D.getLongitude(); int level = position3D.getLevel(); @@ -72,8 +71,8 @@ public class UpperWeatherController { return Result.success(forecastSeries); } - @PostMapping("/queryForecastTimeSeriesInMultiPoints") - public Result queryForecastTimeSeriesInMultiPoints(@Validated @RequestBody MultiPointsRequest multiPointsRequest) { + @PostMapping("/queryUpperForecastInMultiPoints") + public Result queryUpperForecastInMultiPoints(@Validated @RequestBody MultiPointsRequest multiPointsRequest) { List<Double> latitudeList = new ArrayList<>(); List<Double> longitudeList = new ArrayList<>(); for (Position2D position : multiPointsRequest.getPointList()) { @@ -93,6 +92,8 @@ public class UpperWeatherController { return Result.success(nowWeatherByMultiPoint); } + + /**查询指定变量随气压的分布*/ @RequestMapping("/queryProfileByVariableAndPressure") public Result queryProfileByVariableAndPressure(@Validated @RequestBody ProfileRequest profileRequest) { OffsetDateTime time = OffsetDateTime.parse(profileRequest.getTime()); @@ -106,22 +107,34 @@ public class UpperWeatherController { return Result.success(profileResponse); } - @PostMapping("/plane") - public Result queryPlane(@Validated @RequestBody PlaneRequest planeRequest) { + /**查询全部变量随气压的分布*/ + @RequestMapping("/queryProfileByPressure") + public Result queryProfileByAndPressure(@Validated @RequestBody ProfileRequest profileRequest) { + OffsetDateTime time = OffsetDateTime.parse(profileRequest.getTime()); + OffsetDateTime utcDateTime = DateTimeUtils.getUTCDateTime(time); + double latitude = profileRequest.getLatitude(); + double longitude = profileRequest.getLongitude(); + log.info("[data-server] 高度廓线查询 start: param={}", profileRequest); + ProfileDataset profile = gfsDataService.getProfileByPressure(utcDateTime, latitude, longitude); + log.info("[data-server] 高度廓线查询 end"); + return Result.success(profile); + } + + @PostMapping("/queryPlaneGrid") + public Result queryPlaneGrid(@Validated @RequestBody PlaneRequest planeRequest) { planeRequest.valid(); String variableName = planeRequest.getVariableName(); OffsetDateTime time = OffsetDateTime.parse(planeRequest.getTime()); OffsetDateTime utcDateTime = DateTimeUtils.getUTCDateTime(time); int level = planeRequest.getLevel(); - double minLat = planeRequest.getMinLat(); - double maxLat = planeRequest.getMaxLat(); - double minLon = planeRequest.getMinLon(); - double maxLon = planeRequest.getMaxLon(); + double minLat = planeRequest.getMinLatitude(); + double maxLat = planeRequest.getMaxLatitude(); + double minLon = planeRequest.getMinLongitude(); + double maxLon = planeRequest.getMaxLongitude(); log.info("[data-server] 平面网格数据查询 start: param={}", planeRequest); PlaneResponse forecastSeries = gfsDataService.getPlane(utcDateTime, variableName, level, minLat, maxLat, minLon, maxLon); log.info("[data-server] 平面网格数据查询 end"); return Result.success(forecastSeries); } - } diff --git a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/GfsConfigUpdate.java b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/GfsConfigUpdate.java index 0cac655..bdb3c84 100644 --- a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/GfsConfigUpdate.java +++ b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/GfsConfigUpdate.java @@ -1,6 +1,6 @@ package com.htfp.weather.web.pojo.request; -import com.htfp.weather.download.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDataConfig; import lombok.Data; /** 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 da44e2c..570e65e 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 @@ -1,8 +1,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.download.gfs.GfsVariableIsobaricEnum; +import com.htfp.weather.download.gfs.GfsLevelsEnum; import com.htfp.weather.web.exception.AppException; import com.htfp.weather.web.exception.ErrorCode; import com.htfp.weather.web.valid.DateTimeStr; @@ -35,29 +34,29 @@ public class PlaneRequest { @NotNull @Min(value = 70, message = "经度最小值为70(东经180°)") @Max(value = 140, message = "经度最大值为140(东经140°)") - private Double minLon; + private Double minLongitude; @NotNull @Min(value = 70, message = "经度最小值为70(东经180°)") @Max(value = 140, message = "经度最大值为140(东经140°)") - private Double maxLon; + private Double maxLongitude; @NotNull @Min(value = 0, message = "纬度最小值为0(0°)") @Max(value = 55, message = "纬度最大值为55(北纬55°)") - private Double minLat; + private Double minLatitude; @NotNull @Min(value = 0, message = "纬度最小值为0(0°)") @Max(value = 55, message = "纬度最大值为55(北纬55°)") - private Double maxLat; + private Double maxLatitude; public void valid() { // TODO 2024/4/21: 校验 - if (minLon >= maxLon) { + if (minLongitude >= maxLongitude) { throw new AppException(ErrorCode.VALIDATE_ERROR, "最小经度必须小于最大经度"); } - if (minLat >= maxLat) { + if (minLatitude >= maxLatitude) { throw new AppException(ErrorCode.VALIDATE_ERROR, "最小纬度必须小于最大纬度度"); } } diff --git a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/ProfileRequest.java b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/ProfileRequest.java index c13e3cf..59d9ae1 100644 --- a/weather-service/src/main/java/com/htfp/weather/web/pojo/request/ProfileRequest.java +++ b/weather-service/src/main/java/com/htfp/weather/web/pojo/request/ProfileRequest.java @@ -19,7 +19,6 @@ public class ProfileRequest { @DateTimeStr(message = "时间格式错误") String time; - @NotNull(message = "变量名不能为空") String variableName; @NotNull(message = "纬度 (latitude) 不能为空") diff --git a/weather-service/src/main/java/com/htfp/weather/web/pojo/response/ProfileDataset.java b/weather-service/src/main/java/com/htfp/weather/web/pojo/response/ProfileDataset.java new file mode 100644 index 0000000..0e8fafe --- /dev/null +++ b/weather-service/src/main/java/com/htfp/weather/web/pojo/response/ProfileDataset.java @@ -0,0 +1,42 @@ +package com.htfp.weather.web.pojo.response; + +import lombok.Data; + +import java.util.ArrayList; + +/** + * @Author : shiyi + * @Date : 2024/5/8 15:19 + * @Description : 高度廓线 + */ +@Data +public class ProfileDataset { + int[] pressureLevels; + // int[ pressureHeight; + double latitude; + double longitude; + + float[] temp; + float[] windSpeed; + float[] wind360; + // List<String> windScale; + float[] humidity; + // float[] pressure; + float[] cloud; + float[] precip; + + + public ProfileDataset() {}; + public ProfileDataset(int size) { + this.pressureLevels = new int[size]; + // this.pressureHeight = pressureHeight; + temp = new float[size]; + windSpeed = new float[size]; + wind360 = new float[size]; + // windScale = new float[size; + humidity = new float[size]; + // pressure = new float[size; + cloud = new float[size]; + precip = new float[size]; + } +} 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 f9569d5..0d6dc7a 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 @@ -4,21 +4,19 @@ import com.aliyun.tablestore.grid.consts.AttributionEnum; import com.aliyun.tablestore.grid.model.GridDataSet; import com.aliyun.tablestore.grid.model.GridDataSetMeta; import com.aliyun.tablestore.grid.model.grid.Grid4D; -import com.htfp.weather.griddata.common.GfsVariableHeightEnum; -import com.htfp.weather.griddata.common.GfsVariableIsobaricEnum; +import com.htfp.weather.download.gfs.GfsVariableHeightEnum; +import com.htfp.weather.download.gfs.GfsVariableIsobaricEnum; import com.htfp.weather.griddata.common.TableConfig; import com.htfp.weather.griddata.operation.GfsDataFetcher; -import com.htfp.weather.griddata.utils.ValueRange; +import com.htfp.weather.griddata.common.ValueRange; import com.htfp.weather.info.Constant; -import com.htfp.weather.info.GfsLevelsEnum; +import com.htfp.weather.download.gfs.GfsLevelsEnum; import com.htfp.weather.utils.DateTimeUtils; 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; -import com.htfp.weather.web.pojo.response.ProfileResponse; -import com.htfp.weather.web.pojo.response.TimeSeriesDataset; +import com.htfp.weather.web.pojo.response.*; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import ucar.ma2.Array; @@ -30,7 +28,6 @@ import java.time.Duration; import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; import java.util.*; /** @@ -201,9 +198,23 @@ public class GfsDataServiceImpl implements IDataService { } catch (Exception e) { throw new AppException(ErrorCode.TABLESTORE_QUERY_ERROR, e.getMessage()); } - + } + public ProfileDataset getProfileByPressure(OffsetDateTime targetTime, double latitude, double longitude) { + try { + List<String> variableNames = getVariableNamesInDatabase(GfsLevelsEnum.UPPER.getCode()); + GridDataSet gridDataSet = gfsDataFetcher.getProfileByPressure(variableNames, targetTime, latitude, longitude); + ProfileDataset profile = buildProfileDataset(gridDataSet, GfsLevelsEnum.UPPER); + profile.setLatitude(latitude); + profile.setLongitude(longitude); + return profile; + } catch (AppException e) { + throw e; + } catch (Exception e) { + throw new AppException(ErrorCode.TABLESTORE_QUERY_ERROR, e.getMessage()); + } } + /** * 获取指定变量、时间、高度的二维数组数据 * @@ -304,16 +315,7 @@ public class GfsDataServiceImpl implements IDataService { // 利用反射构建数据集 Class<? extends TimeSeriesDataset> aClass = result.getClass(); for (Map.Entry<String, Grid4D> entry : gridDataSet.getVariables().entrySet()) { - String variableNameInFile = entry.getKey(); - String variableNameInApi; - if (GfsLevelsEnum.SURFACE.equals(levelFlag)) { - variableNameInApi = GfsVariableHeightEnum.getVariableNameInApi(variableNameInFile); - } else { - variableNameInApi = GfsVariableIsobaricEnum.getVariableNameInApi(variableNameInFile); - } - if (variableNameInApi == null) { - throw new AppException(ErrorCode.NO_SUCH_VARIABLE); - } + String variableNameInApi = getVariableNameInApi(levelFlag, entry); Grid4D grid4D = entry.getValue(); int[] origin = grid4D.getOrigin(); // grid4D的起始坐标全局索引 int[] shape = grid4D.getShape(); @@ -381,16 +383,7 @@ public class GfsDataServiceImpl implements IDataService { // 利用反射构建数据集 Class<? extends NowWeatherStatus> aClass = result.getClass(); for (Map.Entry<String, Grid4D> entry : gridDataSet.getVariables().entrySet()) { - String variableNameInFile = entry.getKey(); - String variableNameInApi; - if (GfsLevelsEnum.SURFACE.equals(levelFlag)) { - variableNameInApi = GfsVariableHeightEnum.getVariableNameInApi(variableNameInFile); - } else { - variableNameInApi = GfsVariableIsobaricEnum.getVariableNameInApi(variableNameInFile); - } - if (variableNameInApi == null) { - throw new AppException(ErrorCode.NO_SUCH_VARIABLE); - } + String variableNameInApi = getVariableNameInApi(levelFlag, entry); Grid4D grid4D = entry.getValue(); Index4D index = new Index4D(grid4D.getShape()); int[] origin = grid4D.getOrigin(); // grid4D的起始坐标全局索引 try { @@ -410,6 +403,48 @@ public class GfsDataServiceImpl implements IDataService { return result; } + private ProfileDataset buildProfileDataset(GridDataSet gridDataSet, GfsLevelsEnum levelFlag) { + ProfileDataset result = new ProfileDataset(); + // 利用反射构建数据集 + Class<? extends ProfileDataset> aClass = result.getClass(); + for (Map.Entry<String, Grid4D> entry : gridDataSet.getVariables().entrySet()) { + try { + String variableNameInApi = getVariableNameInApi(levelFlag, entry); + Grid4D grid4D = entry.getValue(); + int[] shape = grid4D.getShape(); + int zSize = shape[1]; + String setMethodName = "set" + variableNameInApi.substring(0, 1).toUpperCase() + variableNameInApi.substring(1); + Method method = aClass.getDeclaredMethod(setMethodName, aClass.getDeclaredField(variableNameInApi).getType()); + // TODO 2024/6/20: 这里的toArray操作在数据量较大的时候会比较吃内存和cpu + float[] values = (float[]) grid4D.toArray().section( + new int[]{0, 0, 0, 0}, new int[]{1, zSize, 1, 1} + ).copyTo1DJavaArray(); + method.invoke(result, values); + } catch (ReflectiveOperationException e) { + throw new AppException(ErrorCode.NO_SUCH_VARIABLE, e); + } catch (Exception e) { + e.printStackTrace(); + throw new AppException(ErrorCode.RESPONSE_DATA_BUILD_ERROR); + } + } + result.setPressureLevels(tableConfig.getPressureList()); + return result; + } + + @NotNull + private static String getVariableNameInApi(GfsLevelsEnum levelFlag, Map.Entry<String, Grid4D> variable) { + String variableNameInFile = variable.getKey(); + String variableNameInApi; + if (GfsLevelsEnum.SURFACE.equals(levelFlag)) { + variableNameInApi = GfsVariableHeightEnum.getVariableNameInApi(variableNameInFile); + } else { + variableNameInApi = GfsVariableIsobaricEnum.getVariableNameInApi(variableNameInFile); + } + if (variableNameInApi == null) { + throw new AppException(ErrorCode.NO_SUCH_VARIABLE); + } + return variableNameInApi; + } private Map<String, List> getFutureTimeIndexList(GridDataSetMeta lastGridDataSetMeta) { long milli = (long) lastGridDataSetMeta.getAttributes().get(AttributionEnum.REFERENCE_TIME.getName()); 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 ce73e73..4e7c2b7 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 @@ -15,6 +15,8 @@ import com.htfp.weather.web.pojo.response.TimeSeriesDataset; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -141,7 +143,9 @@ public class CaiYunServiceImpl implements ISurfaceDataService { try { TimeSeriesDataset timeSeriesDataset = new TimeSeriesDataset(24); for (int i = 0; i < 24; i++) { - timeSeriesDataset.getTime().add(hourly.getTemperature().get(i).getDatetime()); + timeSeriesDataset.getTime().add( + OffsetDateTime.parse(hourly.getTemperature().get(i).getDatetime()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + ); timeSeriesDataset.getTemp()[i] = hourly.getTemperature().get(i).getValue(); timeSeriesDataset.getWindSpeed()[i] = (float) MeteoUtils.kmPerHour2mPerSecond(hourly.getWind().get(i).getSpeed()); timeSeriesDataset.getWind360()[i] = hourly.getWind().get(i).getDirection(); 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 4ac416f..7e2eb8e 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 @@ -20,6 +20,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.MessageDigest; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import static com.htfp.weather.utils.HttpClientUtils.*; @@ -194,7 +196,9 @@ public class HeFengServiceImpl implements ISurfaceDataService { List<SurfaceWeatherWarning> surfaceWeatherWarnings = new ArrayList<>(); for (HeFengWarning heFengWarning : heFengWarnings) { SurfaceWeatherWarning surfaceWeatherWarning = new SurfaceWeatherWarning(); - surfaceWeatherWarning.setPubTime(heFengWarning.getPubTime()); + surfaceWeatherWarning.setPubTime( + OffsetDateTime.parse(heFengWarning.getPubTime()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME) + ); // surfaceWeatherWarning.setStartTime(heFengWarning.getStartTime()); surfaceWeatherWarning.setTitle(heFengWarning.getTitle()); surfaceWeatherWarning.setText(heFengWarning.getText()); @@ -213,13 +217,12 @@ public class HeFengServiceImpl implements ISurfaceDataService { * @return */ private BaseHeFengData processHeFengData(BaseHeFengData data) { - String format = Constant.API_TIME_STRING; if (data instanceof HeFengForecastHour) { - String fxTime = DateTimeUtils.getBJTDateTimeStringFromUTC(((HeFengForecastHour) data).getFxTime(), format); - ((HeFengForecastHour) data).setFxTime(fxTime); + String fxTime = ((HeFengForecastHour) data).getFxTime(); + ((HeFengForecastHour) data).setFxTime(OffsetDateTime.parse(fxTime).format(Constant.API_TIME_FORMATTER)); } else if (data instanceof HeFengNow) { - String obsTime = DateTimeUtils.getBJTDateTimeStringFromUTC(((HeFengNow) data).getObsTime(), format); - ((HeFengNow) data).setObsTime(obsTime); + String obsTime = ((HeFengNow) data).getObsTime(); + ((HeFengNow) data).setObsTime(OffsetDateTime.parse(obsTime).format(Constant.API_TIME_FORMATTER)); } float windSpeed = (float) MeteoUtils.kmPerHour2mPerSecond(data.getWindSpeed()); data.setWindSpeed(windSpeed); diff --git a/weather-service/src/test/java/com/htfp/weather/download/GfsDataConfigTest.java b/weather-service/src/test/java/com/htfp/weather/download/GfsDataConfigTest.java index 41957c7..83ab309 100644 --- a/weather-service/src/test/java/com/htfp/weather/download/GfsDataConfigTest.java +++ b/weather-service/src/test/java/com/htfp/weather/download/GfsDataConfigTest.java @@ -1,11 +1,10 @@ package com.htfp.weather.download; +import com.htfp.weather.download.gfs.GfsDataConfig; import org.junit.jupiter.api.Test; import java.io.IOException; -import static org.junit.jupiter.api.Assertions.*; - /** * @Author : shiyi * @Date : 2024/4/21 16:28 diff --git a/weather-service/src/test/java/com/htfp/weather/download/GfsDownloaderTest.java b/weather-service/src/test/java/com/htfp/weather/download/GfsDownloaderTest.java index a1e0b2b..8eba0cf 100644 --- a/weather-service/src/test/java/com/htfp/weather/download/GfsDownloaderTest.java +++ b/weather-service/src/test/java/com/htfp/weather/download/GfsDownloaderTest.java @@ -1,11 +1,11 @@ package com.htfp.weather.download; +import com.htfp.weather.download.gfs.GfsDataConfig; +import com.htfp.weather.download.gfs.GfsDownloader; import org.junit.jupiter.api.Test; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; - /** * @Author : shiyi * @Date : 2024/4/25 16:15 diff --git a/weather-service/src/test/java/com/htfp/weather/griddata/operation/GfsDataFetcherTest.java b/weather-service/src/test/java/com/htfp/weather/griddata/operation/GfsDataFetcherTest.java index 71d1b00..1cd50fb 100644 --- a/weather-service/src/test/java/com/htfp/weather/griddata/operation/GfsDataFetcherTest.java +++ b/weather-service/src/test/java/com/htfp/weather/griddata/operation/GfsDataFetcherTest.java @@ -1,6 +1,6 @@ package com.htfp.weather.griddata.operation; -import com.htfp.weather.griddata.common.GfsVariableIsobaricEnum; +import com.htfp.weather.download.gfs.GfsVariableIsobaricEnum; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -31,7 +31,6 @@ class GfsDataFetcherTest { @Test void getProfile() throws Exception { log.info("获取廓线"); - gfsDataFetcher.getProfile(dataSetId, GfsVariableIsobaricEnum.getGfsVariableName("Temp"), 9,0, 0); } // @Test diff --git a/weather-service/src/test/java/com/htfp/weather/griddata/utils/GfsUtilsTest.java b/weather-service/src/test/java/com/htfp/weather/griddata/utils/GfsUtilsTest.java deleted file mode 100644 index a40da91..0000000 --- a/weather-service/src/test/java/com/htfp/weather/griddata/utils/GfsUtilsTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.htfp.weather.griddata.utils; - -import com.htfp.weather.utils.DateTimeUtils; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import ucar.nc2.NetcdfFile; -import ucar.nc2.NetcdfFiles; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @Author : shiyi - * @Date : 2024/3/4 10:21 - * @Description : - */ -class GfsUtilsTest { - - @Test - void getRefTime() throws IOException { - String filename = "D:\\HTFP\\weather\\GFSData\\UTC-20240607.00\\BJT-20240607.17-from-UTC-20240607.00+9.grib2"; - NetcdfFile ncFile = NetcdfFiles.open(filename); - String refTime = GfsUtils.getRefTime(ncFile); - String s = filename.split("\\+")[1]; - Integer.parseInt(s.split(".grib2")[0]); - // assertEquals("2023-09-05T00:00+00:00", refTime); - // Assertions.assertEquals("2023-09-05T08:00+08:00", DateTimeUtils.getBJTDateTimeStringFromUTC(refTime, CoordinateUtils.DATE_TIME_PATTERN)); - } -} \ No newline at end of file