最可行方案是调用OpenWeatherMap公开API:注册获appid后用Java 11+ HttpClient发请求,传城市ID与units参数,设Accept头防HTML错误页,用Jackson解析JSON并校验字段存在性,加内存缓存与异常兜底。

直接调用公开天气 API 是最可行的路径,自己爬取网页或解析 HTML 容易失效、被封、违反 robots.txt。
选哪个 API:OpenWeatherMap 最适合初学者
OpenWeatherMap 提供免费版(1000 次/天),响应快、文档清晰、支持 JSON,不需要 OAuth 复杂流程。注册后拿到 appid 就能发 HTTP 请求。国内用户要注意它不支持中文城市名直查(如“北京”会返回空),得用英文名("beijing")或城市 ID(推荐)。
- 城市 ID 可在官网搜索后从 URL 或响应中提取,比如北京是
101010100(中国气象局编码)或 OpenWeather 自己的1816670 - 接口地址示例:
https://api.openweathermap.org/data/2.5/weather?id=1816670&appid=YOUR_KEY&units=metric -
units=metric返回摄氏度;用imperial会得华氏度,别漏写
用 HttpURLConnection 还是 HttpClient?推荐 HttpClient(Java 11+ 内置)
Java 11+ 自带 HttpClient,比老式 HttpURLConnection 更简洁、异步友好、自动处理 gzip。别再手写连接、流关闭、字符集设置——这些是初学者最常见的崩溃点。
- 必须显式设
Accept: application/json,否则某些 API 返回 HTML 错误页,JsonParseException就来了 - 记得捕获
IOException和InterruptedException,网络请求可能超时或中断 - 示例关键片段:
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.openweathermap.org/..."))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
解析 JSON 别手写正则或 substring
用 org.json(轻量)或 Jackson(更健壮)解析,避免字符串截取导致的 StringIndexOutOfBoundsException。OpenWeather 的 JSON 结构固定,但字段可能缺失(比如 rain 在无雨时根本不出现)。
立即学习“Java免费学习笔记(深入)”;
- 检查 key 是否存在再取值:
if (obj.has("main")) { obj.getJSONObject("main").getDouble("temp"); } - 温度字段是
main.temp,不是temperature——看文档比猜名字靠谱 - 时间戳字段
dt是 Unix 秒级时间,需转成北京时间:Instant.ofEpochSecond(dt).atZone(ZoneId.of("Asia/Shanghai"))
本地缓存和异常兜底不能省
网络不稳定、API 限流、JSON 字段变更都会让程序崩在生产环境。至少加一层内存缓存(比如 ConcurrentHashMap)和默认值逻辑。
- 缓存键建议用城市 ID + 单位组合,避免 “beijing” 和 “Beijing” 冲突
- HTTP 状态码非 200 时,不要直接抛异常,记录日志并返回
WeatherData.unknown()这类占位对象 - JSON 解析失败时,打印原始
response.body()内容——90% 的解析错误是因为返回了 HTML 错误页(比如 appid 错了返回 401 页面)
真正麻烦的不是发请求或解析 JSON,而是处理城市名映射、时区转换、字段空值、API 响应格式微调——这些细节没覆盖,系统上线第一天就会收告警。











