根据经纬度获取气象数据信息(NOAA)
/ 1. 获取 HTTP 状态码// 2. 如果状态码不是 200,抛出异常if (status!= 200) {// 3. 提取响应体内容(错误详情)// 4. 构造异常信息throw new IOException("API请求失败: HTTP " + status+ "\n响应内容: " + errorBody);常见错误响应HTTP 状态码含义解决方法400参数错误检查datasetdat
·
首先去注册 NOAA API 密钥
通过提供的api去访问
(一)通过经纬度获取附近的气象站id
double lat = 34.2050708; // 纬度(北京)
double lon = 117.2782967; // 经度
String url = BASE_URL + "/stations?" +
"extent=" + (lat - 0.5) + "," + (lon - 0.5) + "," + (lat + 0.5) + "," + (lon + 0.5) + // 近似范围
"&datasetid=GHCND" + // 全球历史气候网络数据集
"&limit=" + 5;
HttpGet request = new HttpGet(url);
request.addHeader("token", API_TOKEN11);
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(request)) {
checkResponse(response);
String json = EntityUtils.toString(response.getEntity());
JsonNode root = mapper.readTree(json);
JsonNode stations = root.get("results");
//气象站id
List<String> ids = new ArrayList<>();
//海拔数据
List<String> elevations = new ArrayList<>();
for (JsonNode station : stations) {
//海拔数据
elevations.add(station.get("elevation").asText());
ids.add(station.get("id").asText());
if (ids.size() >= 5) break;
}
(二)根据获取的气站id去查询气象数据
public static List<WeatherData> fetchTwoYearData(String stationId) throws Exception {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusYears(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String url = BASE_URL + "/data?" +
"datasetid=GHCND" + //日数据
"&stationid=" + stationId +
"&startdate=" + startDate.format(formatter) +
"&enddate=" + endDate.format(formatter) +
"&units=metric" + // 使用公制单位
//"&datatypeid=WSF2" + // 指定风速类型 (AWND:日平均风速 WSF2:日最大风速 WSFG:日最大阵风风速)
"&datatypeid=TMAX,TMIN,TAVG,RH,PRES,DEWP" +
"&limit=1000"; // 单次请求最大数据量
HttpGet request = new HttpGet(url);
request.addHeader("token", API_TOKEN11);
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(request)) {
checkResponse(response);
String json = EntityUtils.toString(response.getEntity());
return parseWeatherData(json);
}
}
private static List<WeatherData> parseWeatherData(String json) throws Exception {
JsonNode root = mapper.readTree(json);
JsonNode results = root.get("results");
List<WeatherData> dataList = new ArrayList<>();
for (JsonNode item : results) {
WeatherData data = new WeatherData();
//气象站id
data.setStationId(item.get("station").asText());
data.setDate(item.get("date").asText());
//数据类型
data.setDataType(item.get("datatype").asText());
data.setValue(item.get("value").doubleValue());
// 解析温度(需根据 datatype 过滤)
if (item.get("datatype").asText().equals("TMAX")) {
data.setMaxTemp(item.get("value").doubleValue());
} else if (item.get("datatype").asText().equals("TMIN")) {
data.setMinTemp(item.get("value").doubleValue());
}
dataList.add(data);
}
return dataList;
}
若是无法查询到WSF2(风速),RH(湿度),PRES(气压),DEWP(露点温度),需要查询当前气象站是否支持查询这些字段
public class StationFieldChecker {
private static final String BASE_URL = "https://www.ncei.noaa.gov/access/services/data/v1";
private static final String API_TOKEN = "YOUR_API_KEY"; // 替换为你的API密钥
/**
* 检查气象站是否支持指定字段
* @param stationId 气象站ID(如GHCND:USW00094728)
* @param fieldsToCheck 需要检查的字段列表(如RH, PRES, DEWP)
* @return 支持的字段Map(字段名 -> 是否支持)
*/
public static Map<String, Boolean> checkSupportedFields(String stationId, List<String> fieldsToCheck) throws IOException {
// 1. 获取站点支持的所有字段
String url = BASE_URL + "/datatypes?stationid=" + stationId + "&limit=1000";
HttpGet request = new HttpGet(url);
request.addHeader("token", API_TOKEN);
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(request)) {
String json = EntityUtils.toString(response.getEntity());
JsonNode dataTypes = new ObjectMapper().readTree(json);
// 2. 提取支持的字段列表
Set<String> supportedFields = new HashSet<>();
for (JsonNode item : dataTypes) {
supportedFields.add(item.path("id").asText().toUpperCase());
}
// 3. 检查目标字段是否在支持列表中
Map<String, Boolean> result = new HashMap<>();
for (String field : fieldsToCheck) {
result.put(field, supportedFields.contains(field.toUpperCase()));
}
return result;
}
}
public static void main(String[] args) throws IOException {
String stationId = "GHCND:USW00094728"; // 纽约中央公园气象站
List<String> fieldsToCheck = Arrays.asList("RH", "PRES", "DEWP", "TMAX", "UNKNOWN_FIELD");
Map<String, Boolean> supportStatus = checkSupportedFields(stationId, fieldsToCheck);
supportStatus.forEach((field, isSupported) ->
System.out.println(field + ": " + (isSupported ? "支持" : "不支持")));
}
}
自定义的一个状态集
private static void checkResponse(CloseableHttpResponse response) throws IOException {
// 1. 获取 HTTP 状态码
int status = response.getStatusLine().getStatusCode();
// 2. 如果状态码不是 200,抛出异常
if (status != 200) {
// 3. 提取响应体内容(错误详情)
String errorBody = EntityUtils.toString(response.getEntity());
// 4. 构造异常信息
throw new IOException("API请求失败: HTTP " + status
+ "\n响应内容: " + errorBody);
}
}
常见错误响应
| HTTP 状态码 | 含义 | 解决方法 |
|---|---|---|
| 400 | 参数错误 | 检查 dataset、dataTypes 拼写 |
| 404 | 站点/数据集不存在 | 验证 stations 和 dataset 名称 |
| 429 | 请求过多 | 降低频率或添加 API 密钥 |
如果返回 403 Forbidden,有可能是token过期或者是api是收费的(检查是否欠费)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)