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

Spring Data如何将@Param标注的YearMonth类型转为起止LocalDate

业务背景

我所维护的产品费率数据按月存储在数据库中,费率生效起始日固定为上月最后一天,失效结束日固定为当月最后一天。例如2020年3月的费率,对应的startDate为2020-02-29,endDate为2020-03-31。

当前实现

现有Rate实体类定义如下:

@Entity
@Data
public class Rate {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name="productId")
    @JsonBackReference
    private Product product;
    
    private LocalDate startDate;
    private LocalDate endDate;
    private BigDecimal value;
    
}

对应Spring Data Repository的查询方法如下:

Rate findByProductIdAndStartDateAndEndDate(
        @Param("productId") Long productId,
        @Param("startDate") @DateTimeFormat(iso=DateTimeFormat.ISO.DATE) LocalDate startDate, 
        @Param("endDate") @DateTimeFormat(iso=DateTimeFormat.ISO.DATE) LocalDate endDate);
需求目标

希望对调用方屏蔽日期计算逻辑,将上述Repository方法改写为直接接收年月参数的形式,可配合@Query注解写JPQL实现:

//OK with writing JPQL here via @Query
Rate findByProductIdAndYearMonth(
        @Param("productId") Long productId,
        @Param("yearMonth") @DateTimeFormat(iso=DateTimeFormat.ISO.DATE) YearMonth yearMonth);
已尝试方案

参考相关资料后考虑过使用AttributeConverter实现转换,但该组件仅支持单字段互转,无法实现单个yearMonth参数映射startDate、endDate两个数据库字段的需求。也考虑过新增Service层封装日期转换逻辑后调用Repository,但当前项目使用Spring Data REST,需要支持客户端直接通过/api/rates/search/findByProductIdAndYearMonth路径调用仓库查询接口,因此需要在Repository层直接实现该能力。


解决方案

推荐使用SpEL表达式在查询生成阶段直接计算出对应的起止日期,完全规避不同数据库的日期函数兼容性问题,实现代码如下:

@Query("SELECT r FROM Rate r WHERE r.product.id = :productId " +
       "AND r.startDate = :#{#yearMonth.minusMonths(1).atEndOfMonth()} " +
       "AND r.endDate = :#{#yearMonth.atEndOfMonth()}")
Rate findByProductIdAndYearMonth(
        @Param("productId") Long productId,
        @Param("yearMonth") YearMonth yearMonth);

上述写法直接调用YearMonth自带的方法计算日期,不需要额外适配数据库,Spring Data REST可以直接暴露该查询接口给客户端调用,完全符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 00:30:03