首先去注册 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 参数错误 检查 datasetdataTypes 拼写
404 站点/数据集不存在 验证 stations 和 dataset 名称
429 请求过多 降低频率或添加 API 密钥

如果返回 403 Forbidden,有可能是token过期或者是api是收费的(检查是否欠费)

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐