SpringBoot调用Strava API空指针问题及认证实现方案咨询
问题根源分析
本次NPE问题和Strava认证逻辑无关,完全是Spring依赖注入使用错误导致,具体原因如下:
@Autowired无法注入静态成员变量。Spring依赖注入的核心是给容器管理的实例对象的成员变量赋值,而static修饰的变量属于类层面的属性,在类加载阶段就完成初始化,早于Spring Bean的初始化流程,因此注入失效,导致activitiesApi始终为null。- Adapter类未被纳入Spring容器管理。你没有给Adapter类加
@Component、@Service等容器注解,Spring不会扫描处理该类的@Autowired注解,就算去掉static修饰也无法完成注入。 - 你在main方法中直接调用静态方法
Adapter.getActivities,此时就算Adapter的实例被注入了属性,静态方法访问的也是类层面的静态变量,依然拿不到Bean实例。
注入问题修复方案
1. 修正Adapter类,交给Spring管理,移除static修饰
@Component public class Adapter { @Autowired private ActivitiesApi activitiesApi; public void getActivities(Integer before, Integer after, Integer page, Integer perPage) { final List<SummaryActivity> loggedInAthleteActivities = activitiesApi.getLoggedInAthleteActivities(before, after, page, perPage); System.out.println("总活动数:"+ loggedInAthleteActivities.size()); } }
2. 修正启动类调用逻辑,从Spring容器中取Adapter实例
@SpringBootApplication @Import(StravaIntegrationConfiguration.class) public class App { public static void main(String[] args) throws SQLException { ConfigurableApplicationContext context = SpringApplication.run(App.class); // 从容器中获取Adapter实例 Adapter adapter = context.getBean(Adapter.class); adapter.getActivities(1636130496, 1635529296, 1, 30); } }
完成以上修改即可解决NPE问题,接下来即可对接Strava的认证逻辑。
Strava OAuth2认证实现示例
Strava使用OAuth2授权码流程认证,你需要先在Strava应用设置中配置回调地址,下面是完整的认证配置:
1. 在application.yml中配置Strava参数
strava: client-id: 你注册应用拿到的client_id client-secret: 你注册应用拿到的client_secret redirect-uri: 你在Strava后台配置的回调地址,比如http://localhost:8080/strava/callback token-url: https://www.strava.com/oauth/token scope: activity:read_all
2. 改造Strava配置类,添加认证逻辑
@Configuration @ConfigurationProperties(prefix = "strava") public class StravaIntegrationConfiguration { private String clientId; private String clientSecret; private String redirectUri; private String tokenUrl; // 省略各属性的getter、setter方法 @Bean public ActivitiesApi stravaApi(ApiClient apiClient){ return new ActivitiesApi(apiClient); } @Bean public ApiClient apiClient(OAuth2AccessToken accessToken){ ApiClient apiClient = new ApiClient(); // 给ApiClient设置认证请求头 apiClient.setAccessToken(accessToken.getValue()); return apiClient; } // 自动刷新token的Bean,首次使用需要先拿到refresh token @Bean public OAuth2AccessToken stravaToken() { // 首次授权可手动拼接授权地址在浏览器打开,授权后拿到code,用code兑换首次的refresh token String refreshToken = "你首次授权拿到的长效refresh_token"; RestTemplate restTemplate = new RestTemplate(); MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("client_id", clientId); params.add("client_secret", clientSecret); params.add("grant_type", "refresh_token"); params.add("refresh_token", refreshToken); ResponseEntity<Map> response = restTemplate.postForEntity(tokenUrl, params, Map.class); Map<String, Object> tokenInfo = response.getBody(); return new DefaultOAuth2AccessToken((String) tokenInfo.get("access_token")); } }
首次获取refresh token方式
拼接如下地址在浏览器打开,登录你的Strava账号授权后,回调地址的参数中会返回授权code:https://www.strava.com/oauth/authorize?client_id=你的client_id&response_type=code&redirect_uri=你的回调地址&scope=activity:read_all
拿到code之后,POST请求https://www.strava.com/oauth/token,携带参数client_id、client_secret、code、grant_type=authorization_code,即可拿到首次的access token和长效refresh token。
内容的提问来源于stack exchange,提问作者Anna Bar
相关产品推荐
相关产品推荐

