Spring Boot:如何在用户输入数据后调用CommandLineRunner?
问题解答
首先明确:CommandLineRunner无法满足你的需求。它是Spring Boot专为应用启动阶段执行一次性初始化逻辑设计的组件,启动完成后不会再被触发,因此不可能在用户输入数据后调用它执行任务。
你的代码还存在两个核心问题:
CovidConfig中的Controller和Date字段未做依赖注入,启动时必然触发空指针;- 即使注入成功,启动阶段用户还未输入日期,
date对象依然为空,同样会引发空指针异常。
正确实现方案
将原CommandLineRunner中的业务逻辑抽成独立服务类,在用户提交日期的POST接口中直接调用该服务,完成数据获取与入库操作。
步骤1:创建Covid数据处理服务类
把数据请求、解析、入库的逻辑封装到专门的服务类中:
package com.andrekreou.covid.gov.service; import com.andrekreou.covid.gov.model.Covid; import com.andrekreou.covid.gov.repository.CovidRepo; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.Collections; import java.util.List; @Service public class CovidDataService { private final CovidRepo covidRepo; private final RestTemplate restTemplate; public CovidDataService(CovidRepo covidRepo, RestTemplate restTemplate) { this.covidRepo = covidRepo; this.restTemplate = restTemplate; } public List<Covid> fetchAndSaveCovidData(String date) { // 生成目标请求URL String url = "https://data.gov.gr/api/v1/query/mdg_emvolio?date_from=" + date + "&date_to=" + date; // 构造请求头 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); headers.set("Authorization","Token 8329eb4fa30e567d9e3f6bfed266c8cb4c9c94ad"); HttpEntity<Object> request = new HttpEntity<>(headers); // 请求第三方API并解析返回结果 ResponseEntity<List<Covid>> response = restTemplate.exchange( url, HttpMethod.GET, request, new ParameterizedTypeReference<List<Covid>>() {} ); // 将数据保存到数据库 List<Covid> covidList = response.getBody(); if (covidList != null && !covidList.isEmpty()) { covidRepo.saveAll(covidList); } return covidList; } }
步骤2:修改Controller的POST接口
用户提交日期后,直接调用服务类方法处理业务:
package com.andrekreou.covid.gov.controller; import com.andrekreou.covid.gov.model.Covid; import com.andrekreou.covid.gov.service.CovidDataService; import com.andrekreou.covid.gov.service.Service; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; import java.util.List; @RestController public class Controller { private final Service service; private final CovidDataService covidDataService; public Controller(Service service, CovidDataService covidDataService) { this.service = service; this.covidDataService = covidDataService; } @GetMapping(path = "/covid") public List<List<Covid>> getData(){ return service.getData(); } @PostMapping(value = "/insert/date") public ModelAndView insertDate(@RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") String date) { // 调用服务类处理数据 List<Covid> covidList = covidDataService.fetchAndSaveCovidData(date); // 返回结果页面(可根据需求调整为JSON响应或重定向) ModelAndView mav = new ModelAndView("result"); mav.addObject("covidList", covidList); return mav; } }
步骤3:简化配置类
移除原CommandLineRunner,仅保留RestTemplate的Bean配置(服务类依赖它发起HTTP请求):
package com.andrekreou.covid.gov.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class CovidConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
步骤4:优化日期输入验证
在Date类中添加日期格式注解,确保用户输入的日期格式符合要求:
package com.andrekreou.covid.gov.model; import org.springframework.format.annotation.DateTimeFormat; public class Date { @DateTimeFormat(pattern = "yyyy-MM-dd") private String date; public String getDate() { return date; } public void setDate(String date) { this.date = date; } }
额外建议
- 异常处理:给RestTemplate调用添加异常捕获逻辑,处理
HttpClientErrorException、HttpServerErrorException等异常,返回友好的错误提示; - 日志记录:在服务类中添加日志,记录数据请求和入库情况,方便排查问题;
- 定时执行需求:如果需要定期同步数据,可以使用Spring的
@Scheduled注解,而非CommandLineRunner。
内容的提问来源于stack exchange,提问作者Alex_Pap
相关产品推荐
相关产品推荐

