JavaFX天气应用切换首个城市触发400错误求助
问题:JavaFX双城市天气预报应用切换第一个城市报错
报错信息
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1787) at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670) ... Caused by: net.aksingh.owmjapis.api.APIException: API call gave error: 400 - Bad Request at owm.japis@2.5.3.0/net.aksingh.owmjapis.core.OWM.hourlyWeatherForecastByCityName(OWM.kt:331) at WeatherApp/com.dariuszkrygier.model.WeatherForecastFetcher.getWeatherForecast(WeatherForecastFetcher.java:16) at WeatherApp/com.dariuszkrygier.controller.MainWindowController.showCurrentWeather(MainWindowController.java:285) at WeatherApp/com.dariuszkrygier.controller.MainWindowController.changeFirstCityLocationButtonAction(MainWindowController.java:202) ... 58 more
问题代码片段
WeatherForecastFetcher.java
public Weather getWeatherForecast(String cityNameWithCountryCode) throws APIException { // 问题行:传入的参数格式无效,触发API 400错误 HourlyWeatherForecast hourlyWeatherForecast = owm.hourlyWeatherForecastByCityName(cityNameWithCountryCode); if (hourlyWeatherForecast.hasRespCode() && hourlyWeatherForecast.getRespCode().equals("200")) { return new Weather(hourlyWeatherForecast); } return null; }
MainWindowController.java
private void showCurrentWeather(TextField locationField, Label locationName, Label locationDate, ImageView locationImage, Label locationTemp, Label locationWeather ) throws APIException { // 问题行:直接传入输入框原始文本,未做清洗校验 var weather = weatherForecastFetcher.getWeatherForecast(locationField.getText()); // ... 后续UI渲染逻辑 } @FXML void changeFirstCityLocationButtonAction() throws APIException { if (firstFieldIsValid()) { // 问题行:未捕获API异常,导致JavaFX线程崩溃 showCurrentWeather(firstCityPicker, firstCity, firstCityFirstDayDate, firstCityFirstDayImage, firstCityFirstDayTemp, firstCityFirstDayDescription ); // ... 其他showNextDays调用 } }
排查分析
- API 400错误本质:OWM API返回400表示请求参数不符合要求,对比第二个城市正常的情况,说明第一个城市的输入存在格式问题(如含多余空格、空字符串、未遵循"城市名,国家代码"的格式规范)。
- 输入校验逻辑薄弱:
firstFieldIsValid()的校验规则可能未过滤无效输入,同时获取输入框文本时未做清洗处理。 - 异常处理缺失:直接抛出APIException未捕获,导致JavaFX应用线程崩溃。
解决方案
1. 清洗输入参数并添加格式校验
修改getWeatherForecast方法,对输入做清洗和格式校验:
public Weather getWeatherForecast(String cityNameWithCountryCode) throws APIException, IllegalArgumentException { // 去除前后空格,避免无效空白字符 String cleanedInput = cityNameWithCountryCode.trim(); // 校验输入非空且符合"城市名,国家代码"格式 if (cleanedInput.isEmpty() || !cleanedInput.contains(",")) { throw new IllegalArgumentException("请输入正确格式:城市名,国家代码(例如:London,UK)"); } HourlyWeatherForecast hourlyWeatherForecast = owm.hourlyWeatherForecastByCityName(cleanedInput); if (hourlyWeatherForecast.hasRespCode() && hourlyWeatherForecast.getRespCode().equals("200")) { return new Weather(hourlyWeatherForecast); } return null; }
2. 完善输入框文本获取逻辑
修改showCurrentWeather中获取输入的代码,确保传入清洗后的文本:
var weather = weatherForecastFetcher.getWeatherForecast(locationField.getText().trim());
3. 强化输入校验规则
更新firstFieldIsValid(),确保过滤无效输入:
private boolean firstFieldIsValid() { String input = firstCityPicker.getText().trim(); // 校验非空且包含逗号分隔符 return !input.isEmpty() && input.contains(","); }
4. 添加异常捕获避免程序崩溃
修改changeFirstCityLocationButtonAction方法,捕获异常并给用户友好提示:
@FXML void changeFirstCityLocationButtonAction() { if (firstFieldIsValid()) { try { showCurrentWeather(firstCityPicker, firstCity, firstCityFirstDayDate, firstCityFirstDayImage, firstCityFirstDayTemp, firstCityFirstDayDescription ); // day2 showNextDays(firstCityPicker, 8, firstCitySecondDayDate, firstCitySecondDayImage, firstCitySecondDayTemp, firstCitySecondDayDescription); // day3 showNextDays(firstCityPicker, 16, firstCityThirdDayDate, firstCityThirdDayImage, firstCityThirdDayTemp, firstCityThirdDayDescription); // day4 showNextDays(firstCityPicker, 24, firstCityFourthDayDate, firstCityFourthDayImage, firstCityFourthDayTemp, firstCityFourthDayDescription); // day5 showNextDays(firstCityPicker, 32, firstCityFifthDayDate, firstCityFifthDayImage, firstCityFifthDayTemp, firstCityFifthDayDescription); } catch (APIException e) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("获取天气失败"); alert.setHeaderText("API请求错误"); alert.setContentText("无法获取天气数据,请检查城市名称是否正确"); alert.showAndWait(); } catch (IllegalArgumentException e) { Alert alert = new Alert(Alert.AlertType.WARNING); alert.setTitle("输入格式错误"); alert.setHeaderText("请检查输入内容"); alert.setContentText(e.getMessage()); alert.showAndWait(); } catch (Exception e) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("程序错误"); alert.setHeaderText("未知错误"); alert.setContentText("操作失败,请重试"); alert.showAndWait(); } } }
内容的提问来源于stack exchange,提问作者dar1o
相关产品推荐
相关产品推荐

