diff --git a/tablestore-grid-master/pom.xml b/tablestore-grid-master/pom.xml
index 5517961..985663d 100644
--- a/tablestore-grid-master/pom.xml
+++ b/tablestore-grid-master/pom.xml
@@ -134,6 +134,9 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ true
+
diff --git a/weather-service/pom.xml b/weather-service/pom.xml
index 9fccfee..5ab3258 100644
--- a/weather-service/pom.xml
+++ b/weather-service/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.htfp
weather-service
- 0.0.1
+ 0.0.3
weather-service
weather-service
jar
@@ -146,6 +146,14 @@
com.htfp.weather.WeatherServiceApplication
ZIP
+
+
+
+ nothing
+ nothing
+
+
+
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 e60827f..072a6b6 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
@@ -20,7 +20,6 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
-import sun.nio.ch.DirectBuffer;
import ucar.ma2.*;
import ucar.nc2.NetcdfFile;
import ucar.nc2.NetcdfFiles;
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 b54d497..efeb997 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
@@ -1,5 +1,8 @@
package com.htfp.weather.utils;
+import com.htfp.weather.utils.ssl.HostInterceptor;
+import com.htfp.weather.utils.ssl.SelectiveHostnameVerifier;
+import com.htfp.weather.utils.ssl.SelectiveTrustManager;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -16,9 +19,17 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
+import javax.net.ssl.*;
+import javax.net.ssl.SSLContext;
+import java.security.SecureRandom;
+
/**
* @Author : shiyi
* @Date : 2024/1/23 16:19
@@ -26,13 +37,36 @@ import java.util.concurrent.TimeUnit;
*/
@Slf4j
public class HttpClientUtils {
+ private static final List TRUSTED_DOMAINS = Arrays.asList("nomads.ncep.noaa.gov");
private static final OkHttpClient OKHTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build();
- private static final OkHttpClient DONLOAD_OKHTTP_CLIENT = new OkHttpClient.Builder()
- .build();
+ private static final OkHttpClient DOWNLOAD_OKHTTP_CLIENT = buildOKHttpClient(TRUSTED_DOMAINS).build();
+
+ public static OkHttpClient.Builder buildOKHttpClient(List trustedDomains) {
+ try {
+ // 1. 创建自定义 TrustManager
+ SelectiveTrustManager trustManager = new SelectiveTrustManager(trustedDomains);
+ // 2. 初始化 SSLContext
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
+ final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.sslSocketFactory(sslSocketFactory, trustManager);
+ builder.addInterceptor(new HostInterceptor());
+ builder.hostnameVerifier(new SelectiveHostnameVerifier(trustedDomains));
+ return builder;
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ e.printStackTrace();
+ return new OkHttpClient.Builder();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new OkHttpClient.Builder();
+ }
+ }
+
// public static T sendGet(String url, Map params, Class responseClass) {
// MultiValueMap queryParams = new LinkedMultiValueMap<>();
// if (params != null) {
@@ -55,6 +89,7 @@ public class HttpClientUtils {
String jsonStr = sendGet(url, params);
return JSONUtils.json2obj(jsonStr, responseClass);
}
+
public static String sendGet(String url, Map params) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
if (!CollectionUtils.isEmpty(params)) {
@@ -98,7 +133,7 @@ public class HttpClientUtils {
.url(sourceUrl)
.build();
- try (Response response = DONLOAD_OKHTTP_CLIENT.newCall(request).execute()) {
+ try (Response response = DOWNLOAD_OKHTTP_CLIENT.newCall(request).execute()) {
if (response.code() == 200) {
assert response.body() != null;
InputStream stream = response.body().byteStream();
diff --git a/weather-service/src/main/java/com/htfp/weather/utils/ssl/HostInterceptor.java b/weather-service/src/main/java/com/htfp/weather/utils/ssl/HostInterceptor.java
new file mode 100644
index 0000000..732702a
--- /dev/null
+++ b/weather-service/src/main/java/com/htfp/weather/utils/ssl/HostInterceptor.java
@@ -0,0 +1,22 @@
+package com.htfp.weather.utils.ssl;
+
+import okhttp3.Interceptor;
+import okhttp3.Response;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+
+public class HostInterceptor implements Interceptor {
+ private static final ThreadLocal hostnameHolder = new ThreadLocal<>();
+
+ @NotNull
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ hostnameHolder.set(chain.request().url().host());
+ return chain.proceed(chain.request());
+ }
+
+ public static String getCurrentHostname() {
+ return hostnameHolder.get();
+ }
+}
diff --git a/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveHostnameVerifier.java b/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveHostnameVerifier.java
new file mode 100644
index 0000000..8e2eeda
--- /dev/null
+++ b/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveHostnameVerifier.java
@@ -0,0 +1,31 @@
+package com.htfp.weather.utils.ssl;
+
+import org.springframework.util.CollectionUtils;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import java.util.Arrays;
+import java.util.List;
+
+public class SelectiveHostnameVerifier implements HostnameVerifier {
+ private List trustedDomains;
+ private final HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+
+ public SelectiveHostnameVerifier(){}
+
+ public SelectiveHostnameVerifier(List trustedDomains) {
+ this.trustedDomains = trustedDomains;
+ }
+
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ if (!CollectionUtils.isEmpty(trustedDomains) && trustedDomains.contains(hostname)) {
+ // 白名单域名:跳过主机名验证
+ return true;
+ } else {
+ // 其他域名:使用默认验证
+ return defaultVerifier.verify(hostname, session);
+ }
+ }
+}
diff --git a/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveTrustManager.java b/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveTrustManager.java
new file mode 100644
index 0000000..fcd5c1d
--- /dev/null
+++ b/weather-service/src/main/java/com/htfp/weather/utils/ssl/SelectiveTrustManager.java
@@ -0,0 +1,79 @@
+package com.htfp.weather.utils.ssl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.CollectionUtils;
+
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import java.security.KeyStore;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+
+@Slf4j
+public class SelectiveTrustManager implements X509TrustManager {
+ // 目标域名白名单(如:example.com)
+ private final List trustedDomains;
+ private final X509TrustManager defaultTrustManager;
+ private final X509TrustManager fakeTrustManager;
+
+ public SelectiveTrustManager(List trustedDomains) throws Exception {
+ this.trustedDomains = trustedDomains;
+ // 获取默认 TrustManager
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+ defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
+
+ // 创建一个“信任所有证书”的 TrustManager(仅用于白名单域名)
+ fakeTrustManager = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ };
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ // 客户端验证交给默认逻辑
+ try {
+ defaultTrustManager.checkClientTrusted(chain, authType);
+
+ } catch (CertificateException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ // 获取当前请求的域名
+ String hostname = getCurrentHostname(); // 需要额外逻辑获取当前域名
+ if (!CollectionUtils.isEmpty(trustedDomains) && trustedDomains.contains(hostname)) {
+ // 白名单域名:跳过证书验证
+ log.debug("{} is in trusted domains, skipping certificate verification", hostname);
+ fakeTrustManager.checkServerTrusted(chain, authType);
+ } else {
+ // 非白名单域名:使用默认验证
+ defaultTrustManager.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return defaultTrustManager.getAcceptedIssuers();
+ }
+
+ // 需要结合 OkHttp 拦截器或反射获取当前请求域名(见后续优化)
+ private String getCurrentHostname() {
+ return HostInterceptor.getCurrentHostname();
+ }
+}
\ No newline at end of file
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 8613db5..7fdcbb0 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
@@ -17,7 +17,7 @@ import com.htfp.weather.web.param.response.DownloadResult;
import com.htfp.weather.web.param.response.ImportResult;
import com.htfp.weather.web.param.response.Result;
import com.htfp.weather.web.service.FileService;
-import com.htfp.weather.web.service.GfsUpperDataServiceImpl;
+import com.htfp.weather.web.service.GfsDataServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.util.CollectionUtils;
@@ -52,7 +52,7 @@ public class ConfigController {
@Resource
FileService fileService;
@Resource
- GfsUpperDataServiceImpl gfsDataService;
+ GfsDataServiceImpl gfsDataService;
@Resource
SurfaceWeatherController surfaceWeatherController;
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 e596e0b..3b38e49 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
@@ -8,7 +8,7 @@ import com.htfp.weather.web.param.response.NowWeatherStatus;
import com.htfp.weather.web.param.response.Result;
import com.htfp.weather.web.param.response.SurfaceWeatherWarning;
import com.htfp.weather.web.param.response.TimeSeriesDataset;
-import com.htfp.weather.web.service.GfsUpperDataServiceImpl;
+import com.htfp.weather.web.service.GfsDataServiceImpl;
import com.htfp.weather.web.service.surfaceapi.CaiYunServiceImpl;
import com.htfp.weather.web.service.surfaceapi.CmaServiceImpl;
import com.htfp.weather.web.service.surfaceapi.HeFengServiceImpl;
@@ -38,7 +38,7 @@ public class SurfaceWeatherController {
@Resource
CaiYunServiceImpl caiYunService;
@Resource
- GfsUpperDataServiceImpl gfsDataService;
+ GfsDataServiceImpl gfsDataService;
ISurfaceDataService service;
@PostConstruct
public void init() {
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 4849003..9c8388c 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
@@ -6,7 +6,7 @@ import com.htfp.weather.web.exception.AppException;
import com.htfp.weather.web.exception.ErrorCode;
import com.htfp.weather.web.param.request.*;
import com.htfp.weather.web.param.response.*;
-import com.htfp.weather.web.service.GfsUpperDataServiceImpl;
+import com.htfp.weather.web.service.GfsDataServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
@@ -29,7 +29,7 @@ import java.util.List;
public class UpperWeatherController {
@Resource(name = "tablestore-gfs")
- GfsUpperDataServiceImpl gfsDataService;
+ GfsDataServiceImpl gfsDataService;
@PostMapping("/queryUpperNowWeather")
@ControllerLog(info = "高空实时气象信息查询")
@@ -50,7 +50,7 @@ public class UpperWeatherController {
List longitudeList = new ArrayList<>(size);
checkLatitudeLongitude(latitudeList, longitudeList, pointList);
int level = multiPointsRequest.getLevel();
- List nowWeatherByMultiPoint = gfsDataService.getNowWeatherByMultiPoint(latitudeList, longitudeList, level);
+ List nowWeatherByMultiPoint = gfsDataService.getNowWeatherByMultiPoint(level, latitudeList, longitudeList);
return Result.success(nowWeatherByMultiPoint);
}
@@ -73,7 +73,7 @@ public class UpperWeatherController {
List longitudeList = new ArrayList<>(size);
checkLatitudeLongitude(latitudeList, longitudeList, pointList);
int level = multiPointsRequest.getLevel();
- List nowWeatherByMultiPoint = gfsDataService.getForecastSeriesByMultiPoint(latitudeList, longitudeList, level);
+ List nowWeatherByMultiPoint = gfsDataService.getForecastSeriesByMultiPoint(level, latitudeList, longitudeList);
return Result.success(nowWeatherByMultiPoint);
}
diff --git a/weather-service/src/main/java/com/htfp/weather/web/param/response/LevelsAvailableResponse.java b/weather-service/src/main/java/com/htfp/weather/web/param/response/LevelsAvailableResponse.java
new file mode 100644
index 0000000..ad3f4b7
--- /dev/null
+++ b/weather-service/src/main/java/com/htfp/weather/web/param/response/LevelsAvailableResponse.java
@@ -0,0 +1,18 @@
+package com.htfp.weather.web.param.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data @NoArgsConstructor @AllArgsConstructor
+public class LevelsAvailableResponse {
+ List levelsAvailableList;
+ @Data @NoArgsConstructor @AllArgsConstructor
+ public static class LevelsAvailable {
+ String dataSource;
+ List pressureLevels;
+ List heightLevels;
+ }
+}
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/GfsUpperDataServiceImpl.java b/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
similarity index 99%
rename from weather-service/src/main/java/com/htfp/weather/web/service/GfsUpperDataServiceImpl.java
rename to weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
index 4de2c27..3cfe3cd 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/GfsUpperDataServiceImpl.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/GfsDataServiceImpl.java
@@ -42,7 +42,7 @@ import java.util.stream.Collectors;
*/
@Service("tablestore-gfs")
@Slf4j
-public class GfsUpperDataServiceImpl implements IUpperDataService, ISurfaceDataService {
+public class GfsDataServiceImpl implements IUpperDataService, ISurfaceDataService {
@Resource
GfsDataFetcher gfsDataFetcher;
@Resource
@@ -163,7 +163,7 @@ public class GfsUpperDataServiceImpl implements IUpperDataService, ISurfaceDataS
* @return
*/
@Override
- public List getNowWeatherByMultiPoint(List latitude, List longitude, int level) {
+ public List getNowWeatherByMultiPoint(int level, List latitude, List longitude) {
if (latitude.size() != longitude.size()) {
throw new AppException(ErrorCode.INDEX_SIZE_ERROR, ": 经纬度数组大小不一致");
}
@@ -233,7 +233,7 @@ public class GfsUpperDataServiceImpl implements IUpperDataService, ISurfaceDataS
* @return
*/
@Override
- public List getForecastSeriesByMultiPoint(List latitudeList, List longitudeList, int level) {
+ public List getForecastSeriesByMultiPoint(int level, List latitudeList, List longitudeList) {
if (latitudeList.size() != longitudeList.size()) {
throw new AppException(ErrorCode.INDEX_SIZE_ERROR, ": 经纬度数组大小不一致");
}
diff --git a/weather-service/src/main/java/com/htfp/weather/web/service/IUpperDataService.java b/weather-service/src/main/java/com/htfp/weather/web/service/IUpperDataService.java
index d25c062..0ac3f14 100644
--- a/weather-service/src/main/java/com/htfp/weather/web/service/IUpperDataService.java
+++ b/weather-service/src/main/java/com/htfp/weather/web/service/IUpperDataService.java
@@ -16,11 +16,11 @@ import java.util.List;
public interface IUpperDataService {
NowWeatherStatus getNowWeather(int level, double latitude, double longitude);
- List getNowWeatherByMultiPoint(List latitude, List longitude, int level);
+ List getNowWeatherByMultiPoint(int level, List latitude, List longitude);
TimeSeriesDataset getForecastSeries(int level, double latitude, double longitude);
- List getForecastSeriesByMultiPoint(List latitudeList, List longitudeList, int level);
+ List getForecastSeriesByMultiPoint(int level, List latitudeList, List longitudeList);
ProfileDataset getProfileByPressure(OffsetDateTime targetTime, double latitude, double longitude);
diff --git a/weather-service/src/main/resources/application.yml b/weather-service/src/main/resources/application.yml
index 266878a..e81e2d4 100644
--- a/weather-service/src/main/resources/application.yml
+++ b/weather-service/src/main/resources/application.yml
@@ -29,3 +29,7 @@ mail:
send:
from: shiyi@htsdfp.com
to: shiyi@htsdfp.com
+
+logging:
+ level:
+ com.htfp.weather: debug
\ No newline at end of file