You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Thymeleaf调用NASA API时出现EL1007E异常求助

问题排查:Spring Boot + Thymeleaf 访问NASA API时出现SpEL空指针异常

运行JUnit测试能正常从NASA API获取JSON对象列表,但Spring Boot结合Thymeleaf展示数据时抛出异常:

org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'photos' cannot be found on null

相关代码

Thymeleaf模板(index.html)

<html xmlns:th="http://thymeleaf.org">
  <head>
    <title>Mars Rover API App</title>
  </head>

  <body>
    <h2>Welcome to the Mars Rover API Web App</h2>
        
    <img th:each="photo : ${roverData.photos}" th:src="${photo.imgSrc}" />   
  </body>
</html>

响应实体类 RoverApiResponse

public class RoverApiResponse {
    private List<MarsPhoto> photos = new ArrayList<>();
    
    public List<MarsPhoto> getPhotos() {
        return photos;
    }

    public void setPhotos(List<MarsPhoto> photos) {
        this.photos = photos;
    }

    @Override
    public String toString() {
        return "MarsRoverApiResponse [photos=" + photos + "]";
    }
}

API服务类 MarsRoverApiService

@Service
public class MarsRoverApiService {
    private final String API_DEMO_LINK= "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=2&api_key=DEMO_KEY"; 

    public String getAPI_DEMO_LINK() {
        return API_DEMO_LINK;
    }

    public RoverApiResponse getRoverData() {
        RestTemplate restTemplate = new RestTemplate();

        ResponseEntity<RoverApiResponse> response = restTemplate.getForEntity(getAPI_DEMO_LINK(), RoverApiResponse.class);
        
        return response.getBody();
    }
}

照片实体类 MarsPhoto

public class MarsPhoto {
    private Long id;
    private Integer sol;
    private Camera camera;

    @JsonProperty("img_src")
    private String imgSrc;

    @JsonProperty("earth_date")
    private Date earthDate;

    private Rover rover;
    
    // 省略getter和setter方法
    @Override
    public String toString() {
        return "MarsPhoto [id=" + id + ", sol=" + sol + ", camera=" + camera + ", imgSrc=" + imgSrc + ", earthDate=" + earthDate + ", rover=" + rover + "]";
    }
}

控制器类 HomeController

@Controller
public class HomeController {

    @Autowired
    private MarsRoverApiService apiService;

    @GetMapping("/")
    public String renderHomePage(ModelMap model) {
        RoverApiResponse roverData = apiService.getRoverData();
        
        model.put("roverData", roverData);
        return "index";
    }

}

异常原因分析

异常明确说明模板中${roverData.photos}里的roverData为null,即apiService.getRoverData()返回了null。JUnit测试正常但Web环境异常,可能的核心原因:

  1. RestTemplate配置缺失:JUnit测试可能手动配置了Jackson消息转换器,但Web环境中每次新建的RestTemplate缺少JSON反序列化能力,导致无法解析API响应为实体类。
  2. 实体类映射不完整:Camera、Rover等嵌套类未添加@JsonProperty注解,或字段类型与API响应不匹配,导致反序列化失败。
  3. 网络访问限制:Web环境存在代理、防火墙等限制,无法正常请求NASA API,返回null。
  4. API响应结构不匹配:实体类未覆盖API响应的所有必要字段,导致RestTemplate无法完成反序列化。

解决方法

1. 标准化RestTemplate配置

通过配置类创建全局RestTemplate实例,确保加载Jackson消息转换器:

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ObjectMapper objectMapper) {
        RestTemplate restTemplate = new RestTemplate();
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(objectMapper);
        restTemplate.getMessageConverters().add(converter);
        return restTemplate;
    }
}

修改MarsRoverApiService注入RestTemplate,而非每次新建:

@Service
public class MarsRoverApiService {
    private final String API_DEMO_LINK= "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=2&api_key=DEMO_KEY"; 
    private final RestTemplate restTemplate;

    public MarsRoverApiService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public RoverApiResponse getRoverData() {
        try {
            ResponseEntity<RoverApiResponse> response = restTemplate.getForEntity(getAPI_DEMO_LINK(), RoverApiResponse.class);
            // 打印响应信息用于排查
            System.out.println("Response Status: " + response.getStatusCode());
            return response.getBody();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

2. 完善实体类JSON映射

为嵌套类Camera、Rover添加@JsonProperty注解,确保字段与API响应匹配:

public class Camera {
    @JsonProperty("id")
    private Long id;
    @JsonProperty("name")
    private String name;
    // 补充其他字段及getter/setter
}

public class Rover {
    @JsonProperty("id")
    private Long id;
    @JsonProperty("name")
    private String name;
    // 补充其他字段及getter/setter
}

对日期字段指定格式,避免解析失败:

@JsonProperty("earth_date")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date earthDate;

3. 模板添加空值防护

在Thymeleaf模板中增加空值判断,避免直接访问null对象的属性:

<div th:if="${roverData != null}">
    <img th:each="photo : ${roverData.photos}" th:src="${photo.imgSrc}" />
</div>
<div th:if="${roverData == null}">
    <p>加载火星车数据失败,请稍后重试。</p>
</div>

4. 排查网络问题

通过捕获异常并打印日志,确认Web环境是否能正常访问NASA API,若存在网络限制需调整环境配置。


内容的提问来源于stack exchange,提问作者Misanty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 03:50:38