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

Spring控制器请求参数绑定多构造器对象如何指定使用的构造方法

问题原因说明

Spring MVC在绑定GET请求的自定义对象参数时,默认会优先查找类的无参构造方法实例化对象,再通过Setter注入属性;如果没有无参构造,就要求类只有唯一的公有构造方法。你当前的DateRange有两个公有构造方法,也没有无参构造,所以Spring无法确定使用哪个构造方法,就抛出了对应的异常。

解决方案

方法1:使用@ConstructorProperties指定主构造方法

这是最贴合你需求的方案,不需要修改原有类结构,直接在你要优先使用的双参数构造方法上添加JDK自带的java.beans.ConstructorProperties注解,明确构造参数对应类的属性名即可:

public class DateRange {

    @DateTimeFormat(iso=DateTimeFormat.ISO.DATE)
    private YearMonth start;    

    @DateTimeFormat(iso=DateTimeFormat.ISO.DATE)
    private YearMonth end;

    // 加该注解指定优先使用该构造方法,参数对应start、end属性
    @ConstructorProperties({"start", "end"})
    public DateRange(YearMonth start, YearMonth end) {
           this.start = start;
           this.end = end;
    }
            
    public DateRange(YearMonth end, Period period) {            
        this(end.minus(period.minusMonths(1)), end);
    }
}

Spring会自动识别该注解,使用指定构造方法完成参数绑定,传入的2021-01-01格式的日期会被@DateTimeFormat自动转换为YearMonth类型,不需要额外处理日期格式。如果是JDK9+模块化环境无法使用该注解,可以使用下面的方法2。

方法2:补充无参构造+Setter方法

如果你允许修改DateRange的结构,直接补充无参构造方法和对应属性的Setter,Spring会先实例化对象再通过Setter注入属性,也能解决问题:

public class DateRange {

    @DateTimeFormat(iso=DateTimeFormat.ISO.DATE)
    private YearMonth start;    

    @DateTimeFormat(iso=DateTimeFormat.ISO.DATE)
    private YearMonth end;

    // 新增无参构造
    public DateRange() {
    }

    public DateRange(YearMonth start, YearMonth end) {
           this.start = start;
           this.end = end;
    }
            
    public DateRange(YearMonth end, Period period) {            
        this(end.minus(period.minusMonths(1)), end);
    }

    // 新增Setter方法
    public void setStart(YearMonth start) {
        this.start = start;
    }

    public void setEnd(YearMonth end) {
        this.end = end;
    }
}

方法3:自定义参数解析器(适配复杂场景)

如果后续有更复杂的DateRange绑定逻辑,可以自定义参数解析器手动控制实例化逻辑:

  1. 实现解析器
public class DateRangeArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(DateRange.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String startStr = webRequest.getParameter("start");
        String endStr = webRequest.getParameter("end");
        YearMonth start = YearMonth.parse(startStr, DateTimeFormatter.ISO_DATE);
        YearMonth end = YearMonth.parse(endStr, DateTimeFormatter.ISO_DATE);
        // 手动选择你需要的构造方法创建对象
        return new DateRange(start, end);
    }
}
  1. 注册到Spring MVC配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new DateRangeArgumentResolver());
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 14:45:03