有这么一个场景,假设前台传递给我们三个参数 id、name、age ,我们很自然的会想到使用 @RequestParam 来接收前台传递过来的参数,具体示例如下
@GetMapping("/getUserInfo")
public String getUserInfo(
// 将前台传递过来的参数 id 对应的值绑定至 Integer 类型的参数 id
// required 的默认值是 true,如果前台传递过来没有该参数,那么就会进行校验并报错
// 当 required = false 时,如果没有传递参数 id,那么它不会报错,而是使用默认值 10086
@RequestParam(value="id",required = false,defaultValue = "10086") Integer id,
@RequestParam(value="name",required = false,defaultValue = "xiaomaomao") String name,
@RequestParam(value = "age",required = false,defaultValue = "21") Integer age) {
return "id===" + id + " name===" + name + " age===" + age;
}
上面的示例看起来没有什么问题,可是实际上我们不难发现,如果前台传递过来的参数不是三个,而是十个,如果继续使用 @RequestParam 的方式来接收请求参数,就需要十个 @RequestParam ,我们的代码可读性将会变得很差,并且当参数类型相同时,十分容易出错,有没有什么好的解决方案呢?
这个时候可能你会想到使用实体类来接收传递过来的十个参数,想法是正确的,可是 @RequestParam 不支持直接传递实体类的方式,那么有其它的解决办法吗?
答案是有的,具体示例如下
@GetMapping("/getUserInfo")
// 将请求参数中的 id、name、age 与实体类 saleman 进行绑定
public String getUserInfo(Saleman saleman) {
return saleman.toString();
}
很简单,只需要定义一个实体类就能完美解决,可是,如果要实现类似于 @RequestParam(required=true) 的校验该怎么办呢?
其实也好办,我们可以在实体类里面进行校验
@Data
public class Saleman {
// id 最小值为 100
@Min(1)
// id 不能为空,否则会报错
@NonNull
private Integer id;
// 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
@NotBlank
private String name;
// age 最大值为 30
@Max(30)
// age 不能为空,否则校验不通过
@NonNull
private Integer age;
}
注意你如果想要这些实体类中的注解生效,就必须要加上 @Valid 注解
@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman) {
return saleman.toString();
}
这样,我们就模拟出了 @RequestParam(required=true) 的情形了,但是 @RequestParam 注解的作用还包括,如果未提供具体的参数,它会有默认值,这个该怎么实现呢?
做法很简单,只需要在声明实体类属性的时候给一个默认值即可,类似 private Integer id = 2
@Data
public class Saleman {
// id 最小值为 100
@Min(1)
// id 不能为空,否则会报错
@NonNull
// 如果前台没有传递 id 参数,那么 id 会有默认值 2,注意这里的默认值一定要符合上面 @Min、@Nonnull 等注解的校验,否则该默认值设置的是不合理的
private Integer id = 2;
// 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
@NotBlank
private String name = "xiaomaomi";
// age 最大值为 30
@Max(30)
// age 不能为空,否则校验不通过
@NonNull
private Integer age = 28;
}
@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman) {
return saleman.toString();
}
到此,我们就已经模拟出了 @RequestParam 注解的所有功能(空值校验、空值时的默认值)
有时候根据业务需求,不会把所有的请求参数封装进同一个实体类中,我们可以将其封装进多个实体类中,具体的用法同上面一个实体类的相同
@Data
public class Saleman {
// id 最小值为 100
@Min(1)
// id 不能为空,否则会报错
@NonNull
// 如果前台没有传递 id 参数,那么 id 会有默认值 2,注意这里的默认值一定要符合上面 @Min、@Nonnull 等注解的校验,否则该默认值设置的是不合理的
private Integer id = 2;
// 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
@NotBlank
private String name = "xiaomaomi";
// age 最大值为 30
@Max(30)
// age 不能为空,否则校验不通过
@NonNull
private Integer age = 28;
}
@Data
public class Product {
@Min(100)
@NonNull
private Integer id = 10001;
@NotBlank
private String productName = "yishengwenhou";
}
@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman,@Valid Product product) {
return saleman.toString() + "--------" + product.toString();
}
但是有一个需要注意的地方,如果两个实体类中有相同的属性,那么前台传入的参数值会同时封装进入两个实体类中,例如前台传入一个 id,而 Saleman、Product 两个实体类都有 id 这个属性,那么 id 对应的参数值就同时封装进了 saleman、product