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

Spring Boot启动时获取汇率API数据并通过JPA存储的实现咨询

Spring Boot启动时加载汇率API数据并存储到数据库的解决方案

嘿,我来帮你搞定这个启动加载和存储的逻辑!先梳理下你现有代码里的小细节,再一步步实现你要的功能:

第一步:修正模型类的小问题

首先你的CurrencyData里的base和date字段用了@Embedded,这不对——它们是普通字符串,不是嵌入实体,直接去掉这个注解就行。另外Rates类里的HKD字段没写完,得补全;还要给实体类加上无参构造,JPA要求实体必须有一个无参构造方法,不然会报错。修正后的代码如下:

// 修正后的CurrencyData
@Data
@AllArgsConstructor
@NoArgsConstructor // 新增无参构造,JPA必需
@Entity
public class CurrencyData {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @SerializedName("rates")
    @Expose
    @Embedded
    private Rates rates;
    @SerializedName("base")
    @Expose
    private String base; // 去掉@Embedded
    @SerializedName("date")
    @Expose
    private String date; // 去掉@Embedded
}

// 补全后的Rates
@Data
@Embeddable
public class Rates {
    protected Rates(){} // JPA需要无参构造
    @SerializedName("CAD")
    @Expose
    private Double cAD;
    @SerializedName("HKD")
    @Expose
    private Double hKD; // 补全字段定义
    // 可按需添加其他汇率字段,比如USD、EUR等
}

第二步:完善启动加载逻辑(CommandLineRunner)

你已经选对了用CommandLineRunner实现启动时执行逻辑,现在只需要注入你写好的ConnectService、GsonConvert和CurrencyRepository,按顺序调用方法完成数据获取→反序列化→存储的流程:

@Configuration
public class CurrencyDataLoader {

    @Bean
    CommandLineRunner currencyDataLoader(
            ConnectService connectService,
            GsonConvert gsonConvert,
            CurrencyRepository currencyRepository
    ) {
        return args -> {
            // 1. 调用API获取JSON字符串
            String apiResponse = connectService.connect();
            // 2. 反序列化为CurrencyData对象
            CurrencyData currencyData = gsonConvert.gsonCurrency(apiResponse);
            // 3. 保存到数据库
            currencyRepository.save(currencyData);
            System.out.println("汇率数据已成功加载并存储到数据库!");
        };
    }
}

这样Spring Boot启动时,这个Runner会自动执行,帮你完成所有操作。

关于你提到的Map实现思路

如果不想为每个汇率字段都定义属性,确实可以用Map<String, Double>来接收所有汇率数据,这样就不需要Rates类了。修改后的模型类如下:

// 改用Map接收汇率的CurrencyData
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class CurrencyData {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @SerializedName("rates")
    @Expose
    @ElementCollection // 用这个注解存储Map类型的嵌入数据
    private Map<String, Double> rates;
    @SerializedName("base")
    @Expose
    private String base;
    @SerializedName("date")
    @Expose
    private String date;
}

Gson会自动把JSON里的rates对象转换成Map<String, Double>,JPA也会用@ElementCollection把这个Map存储到关联表(默认表名为currency_data_rates,包含currency_data_id、rates_key、rates_value三个字段)。你的GsonConvert代码不需要改动,依然可以正常反序列化。

额外优化建议

  • 完善ConnectService里的异常处理,把你写的TODO替换成自定义异常或合适的RuntimeException;
  • 添加重复数据判断,避免每次启动都存储相同数据:
    在CurrencyRepository里新增查询方法:
    @Repository
    public interface CurrencyRepository extends JpaRepository<CurrencyData, Long> {
        Optional<CurrencyData> findByBaseAndDate(String base, String date);
    }
    
    然后在CommandLineRunner里添加判断逻辑:
    Optional<CurrencyData> existingData = currencyRepository.findByBaseAndDate(currencyData.getBase(), currencyData.getDate());
    if (existingData.isEmpty()) {
        currencyRepository.save(currencyData);
        System.out.println("汇率数据已成功加载并存储到数据库!");
    } else {
        System.out.println("当天的汇率数据已存在,无需重复存储");
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:42:54