有这么一个场景,假设前台传递给我们三个参数 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