SpringMVC接收参数详解—自定义对象篇

SpringMVC接收参数详解—自定义对象篇

相信小伙伴们都会有给controller传参的经历,但是springmvc内部是如何处理这些参数的。今天就带大家来看一看自定义对象情况下的实现。

一、普通实体类参数

@GetMapping("/test1")
public String test1(LoginParam loginParam){
     System.out.println(loginParam);
     return "test1";
}

@Data
@AllArgsConstructor
//@NoArgsConstructor
public class LoginParam{
    String username;
    String password;
}

框架行为详解:

在无参和有参构造都有的情况下,会先调用LoginParam的 无参构造 方法,若传入的参数符合条件,再调用set方法。

如果没有无参构造方法(即只有有参构造,有参构造会覆盖默认的无参构造方法),则先调用 有参构造 方法,若传入的参数符合条件,再调用set方法

下面我们分几类情况来讨论

1.不传或传入的参数名和形参对象属性名不匹配
  • 无参构造(也有有参构造,下述同):调用无参构造方法,类似于new LoginParam(),因为没有传入username和password,所以不调用set方法

  • 只有 有参构造:调用有参构造方法,new LoginParam(null,null),因为没有传入username和password,所以不调用set方法

2.传入正确username、password(即使是username=&password=,即不写参数值)
  • 无参构造:调用无参构造方法,new LoginParam(),因为传入了username和password,所以调用set方法void setUsername(username) void setPassword(password)

  • 只有 有参构造:调用有参构造方法,new LoginParam(username,password),因为传入了username和password,所以调用set方法void setUsername(username) void setPassword(password)

3.只传入username,不传password
  • 无参构造:调用无参构造方法,new LoginParam(),因为传入了username,所以调用set方法void setUsername(username)

  • 只有 有参构造:调用有参构造方法,new LoginParam(username,null),因为传入了username,所以调用set方法void setUsername(username)

4.总结

通过上述我们发现,当LoginParam有 无参构造 方法但没有set方法时,即使我们传入username、password,它也不能正确接受。所以我们要杜绝这种现象。

所以可以避免错误发生的解决方案是:只提供有参构造,这样就不用担心有没有写set方法,如果参数传对了可以接受参数,如果传错了也可以构造空的参数

二、@RequestBody实体类参数

@GetMapping("/test2")
public String test2(@RequestBody LoginParam loginParam)
{
     System.out.println(loginParam);
     return "test2";
}

@Data
@AllArgsConstructor
//@NoArgsConstructor
public class LoginParam{
    String username;
    String password;
}

框架行为详解:

若请求体没数据或不满足json格式,则直接抛异常

若请求体满足json格式,会先调用LoginParam的 无参构造 方法,若传入的参数符合条件,再调用set方法

如果没有无参构造方法,则先调用 有参构造 方法,不会再调用set方法

下面我们分几类情况来讨论

0.不传或不满足json格式

抛异常

1.传入的参数名和形参对象属性名不匹配(但json格式正确)
  • 无参构造:调用无参构造方法,类似于new LoginParam(),因为没有传入username和password,所以不调用set方法

  • 只有 有参构造:调用有参构造方法,new LoginParam(null,null)

2.传入正确username、password
  • 无参构造:调用无参构造方法,new LoginParam(),因为传入了username和password,所以调用set方法void setUsername(username) void setPassword(password)

  • 只有 有参构造:调用有参构造方法,new LoginParam(username,password)

3.只传入username,不传password
  • 无参构造:调用无参构造方法,new LoginParam(),因为传入了username,所以调用set方法void setUsername(username)

  • 只有 有参构造:调用有参构造方法,new LoginParam(username,null)

4.总结

同理,当有 无参构造 方法但没有set方法时,即使我们传入username、password,它也不能正确接受

我们可以同样:只提供有参构造,这样就不用担心有没有写set方法,如果参数传对了可以接受参数,如果传错了也可以构造空的参数

三、结合SpringValidation框架

按照上述思路,我们只提供 有参构造,java中帮我们封装好了一个类:Record,它默认只包含全参构造。在这种情况下又分下列几种错误传参的情况:

1.普通实体类参数
  • 不传或传入的参数名和形参对象属性名不匹配,则调用有参构造方法new LoginParam(null,null)
2.@RequestBody
  • 不传或不满足json格式,则框架抛异常
  • 传入的参数名和形参对象属性名不匹配(但json格式正确,例如空json),则调用有参构造方法new LoginParam(null,null)
3.路径参数
  • 不可能为null,因为如果为null,url都不匹配
4.普通参数
  • 可能为null
  • @Max,@Size注解无法校验是否为 null,因此前面要配合@NotNull或@NotBlank注解

注意:@Validated/@Valid 的验证逻辑是:先检查 obj 不为空,再逐个检查 obj 中各个字段的约束。只有加上@Validated/@Valid,实体类中的@NotNull等注解才会生效

在默认配置下,Spring MVC并不会自动验证简单类型的方法参数(如Stringint等)。若要让这些约束注解生效,需要在控制器方法参数前使用@Valid@Validated注解来触发验证

@Validated/@Valid是等构造函数和set方法完了以后,再开始检查各个字段是否符合注解约束

四、特殊情况

@Data
public class PageRequest{
    @NotNull
    @Min(1)
    private Integer current=1;

    @NotNull
    @Min(1)
    private Integer size=10;
}

如果在字段中直接给出了值,那么字段在调用构造方法前,默认就是这个值。否则默认是为:对象则为null,基本类型则为0 etc…

下面也来分情况讨论

1.不传或传入的参数名和形参对象属性名不匹配
  • 无参构造:调用无参构造方法,类似于new PageRequest(),因为没有传入current和size,所以不调用set方法
    此时current=1,size=10

  • 只有 有参构造:调用有参构造方法,new PageRequest(null,null),因为没有传入current和size,所以不调用set方法。此时current=null,size=null

2.传入正确current、size(即使是current=&size=,即不写参数值)
  • 无参构造:调用无参构造方法,new PageRequest(),因为传入了current和size,所以调用set方法void setCurrent(current) void setSize(size)
    此时current=传入的值,size=传入的值(若不写参数值,则传入的值为null,下述同)

  • 只有 有参构造:调用有参构造方法,new PageRequest(current,size),因为传入了current和size,所以调用set方法void setCurrent(current) void setSize(size)
    此时current=传入的值,size=传入的值

3.只传入current,不传size
  • 无参构造:调用无参构造方法,new PageRequest(),因为传入了current,所以调用set方法void setCurrent(current)
    此时current=传入的值,size=10

  • 只有 有参构造:调用有参构造方法,new PageRequest(current,null),因为传入了current,所以调用set方法void setCurrent(current)
    此时current=传入的值,size=null

4.总结

如果在字段中给出了值,那么不要只写全参构造方法,要给出无参构造。

无参构造中,如果没有传入current和size,那么则为字段中给出的值。如果传入了current和size,那么会调用set方法,set成传入的值。

有参构造中,如果如果没有传入current和size,那么调用构造函数后current和size都为null。如果传入了current和size,则为传入的值。所以字段中提前给出的值不会起作用。

五、正确使用方式

使用java record类来充当dto和vo,因为它默认只包含全参构造。所以无论是错误还是正确的参数都能应对。同时加上@Validated/@Valid注解,这样如果参数不对还能进行校验。

如果要提前给字段赋值,那么用class类(record中不允许给属性赋值,因为属性值默认修饰符为final,默认给出的全参构造赋值时就会报错),给出无参构造。如果没有传入参数,那么则为字段中给出的值。如果传入了参数,那么会调用set方法,set成传入的值。

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值